Skip to content

Commit 3c39957

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 (cherry picked from commit 0989f43)
1 parent 11e3d00 commit 3c39957

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

lib/Sema/CSClosure.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,34 @@ class TypeVariableRefFinder : public ASTWalker {
8585
}
8686

8787
inferVariables(type);
88+
return {true, expr};
89+
}
90+
91+
auto var = dyn_cast<VarDecl>(decl);
92+
if (!var)
93+
return {true, expr};
94+
95+
if (auto *wrappedVar = var->getOriginalWrappedProperty()) {
96+
auto outermostWrapperAttr =
97+
wrappedVar->getAttachedPropertyWrappers().front();
98+
99+
// If the attribute doesn't have a type it could only mean
100+
// that the declaration was incorrect.
101+
if (!CS.hasType(outermostWrapperAttr->getTypeExpr()))
102+
return {true, expr};
103+
104+
auto wrapperType =
105+
CS.simplifyType(CS.getType(outermostWrapperAttr->getTypeExpr()));
106+
107+
if (var->getName().hasDollarPrefix()) {
108+
// $<name> is the projected value var
109+
CS.setType(var, computeProjectedValueType(wrappedVar, wrapperType));
110+
} else {
111+
// _<name> is the wrapper var
112+
CS.setType(var, computeWrappedValueType(wrappedVar, wrapperType));
113+
}
114+
115+
return {true, expr};
88116
}
89117
}
90118

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)