Skip to content

Commit 0989f43

Browse files
committed
[CSClosure] Add support for projected/wrapper values
To support referencing projected and/or wrapped var in a closure solver needs to lookup a type of their originator and based on the wrapper type compute and assign types to projection and/or wrapper. Resolves: #59295 Resolves: rdar://94506352
1 parent 3e65a7c commit 0989f43

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

lib/Sema/CSClosure.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,29 @@ class TypeVariableRefFinder : public ASTWalker {
9696
if (!var)
9797
return {true, expr};
9898

99+
if (auto *wrappedVar = var->getOriginalWrappedProperty()) {
100+
auto outermostWrapperAttr =
101+
wrappedVar->getAttachedPropertyWrappers().front();
102+
103+
// If the attribute doesn't have a type it could only mean
104+
// that the declaration was incorrect.
105+
if (!CS.hasType(outermostWrapperAttr->getTypeExpr()))
106+
return {true, expr};
107+
108+
auto wrapperType =
109+
CS.simplifyType(CS.getType(outermostWrapperAttr->getTypeExpr()));
110+
111+
if (var->getName().hasDollarPrefix()) {
112+
// $<name> is the projected value var
113+
CS.setType(var, computeProjectedValueType(wrappedVar, wrapperType));
114+
} else {
115+
// _<name> is the wrapper var
116+
CS.setType(var, computeWrappedValueType(wrappedVar, wrapperType));
117+
}
118+
119+
return {true, expr};
120+
}
121+
99122
// If there is no type recorded yet, let's check whether
100123
// it is a placeholder variable implicitly generated by the
101124
// compiler.

validation-test/Sema/type_checker_crashers_fixed/issue59294.swift

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %target-typecheck-verify-swift
22

33
// https://github.com/apple/swift/issues/59294
4+
// https://github.com/apple/swift/issues/59295
45

56
@propertyWrapper
67
struct WrapperValue<Value> {
@@ -25,18 +26,94 @@ struct WrapperValue<Value> {
2526
func printValue() {
2627
print(value)
2728
}
29+
30+
func returnValue() -> Value {
31+
return value
32+
}
2833
}
2934

35+
@propertyWrapper
36+
struct OuterWrapper<Value> {
37+
var value: Value
38+
init(wrappedValue: Value) {
39+
self.value = wrappedValue
40+
}
41+
42+
var projectedValue: Self {
43+
return self
44+
}
45+
46+
var wrappedValue: Value {
47+
get {
48+
self.value
49+
}
50+
set {
51+
self.value = newValue
52+
}
53+
}
54+
}
3055

3156
class Test {
3257
static func test() {
3358
return [0, 1, 2].compactMap { _ in // expected-error {{unexpected non-void return value in void function}} expected-note {{did you mean to add a return type?}}
3459
@WrapperValue var value: Bool? = false
3560
if value != nil {
61+
$value.printValue()
3662
return false
3763
}
3864

3965
return value ?? false
4066
}
4167
}
68+
static func testProjectedAndWrapperVars() {
69+
func test(_: (Int) -> Bool) {}
70+
func test(_: (String) -> Void) {}
71+
72+
test {
73+
@WrapperValue var value = $0
74+
if $value.returnValue() > 0 {
75+
test {
76+
return $value.returnValue() == $0 &&
77+
_value == $0
78+
}
79+
}
80+
return false
81+
}
82+
83+
test {
84+
@WrapperValue var value = $0
85+
86+
test {
87+
if _value != $0 { // Ok
88+
$value.printValue()
89+
}
90+
}
91+
}
92+
}
93+
94+
static func testNestedWrappers() {
95+
func test(_: (Bool) -> Void) {}
96+
func test(_: () -> Void) {}
97+
98+
test {
99+
if true {
100+
@OuterWrapper @WrapperValue var value = $0
101+
if true {
102+
let _: Bool = _value == $0
103+
let _: OuterWrapper<WrapperValue<Bool>> = $value
104+
let _: Bool = value
105+
}
106+
}
107+
}
108+
}
109+
110+
static func invalidVar() {
111+
_ = [0, 1, 2].compactMap {
112+
@WrapperValue var value: Bool? = $0
113+
// expected-error@-1 {{cannot convert value of type 'Int' to specified type 'Bool?'}}
114+
if true {
115+
$value.printValue()
116+
}
117+
}
118+
}
42119
}

0 commit comments

Comments
 (0)