Skip to content

Commit 50204e0

Browse files
authored
Merge pull request #60409 from xedin/rdar-94506352-aux-vars-5.7
[5.7][CSClosure] Add support for projected/wrapper values
2 parents 6e02942 + d5e963b commit 50204e0

File tree

8 files changed

+127
-8
lines changed

8 files changed

+127
-8
lines changed

include/swift/AST/Decl.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5430,6 +5430,20 @@ class VarDecl : public AbstractStorageDecl {
54305430
/// is provided first.
54315431
llvm::TinyPtrVector<CustomAttr *> getAttachedPropertyWrappers() const;
54325432

5433+
/// Retrieve the outermost property wrapper attribute associated with
5434+
/// this declaration. For example:
5435+
///
5436+
/// \code
5437+
/// @A @B @C var <name>: Bool = ...
5438+
/// \endcode
5439+
///
5440+
/// The outermost attribute in this case is `@A` and it has
5441+
/// complete wrapper type `A<B<C<Bool>>>`.
5442+
CustomAttr *getOutermostAttachedPropertyWrapper() const {
5443+
auto wrappers = getAttachedPropertyWrappers();
5444+
return wrappers.empty() ? nullptr : wrappers.front();
5445+
}
5446+
54335447
/// Whether this property has any attached property wrappers.
54345448
bool hasAttachedPropertyWrapper() const;
54355449

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6532,7 +6532,7 @@ bool VarDecl::hasExternalPropertyWrapper() const {
65326532
return true;
65336533

65346534
// Wrappers with attribute arguments are always implementation-detail.
6535-
if (getAttachedPropertyWrappers().front()->hasArgs())
6535+
if (getOutermostAttachedPropertyWrapper()->hasArgs())
65366536
return false;
65376537

65386538
auto wrapperInfo = getAttachedPropertyWrapperTypeInfo(0);

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8564,8 +8564,8 @@ static Optional<SolutionApplicationTarget> applySolutionToInitialization(
85648564
wrappedVar, initType->mapTypeOutOfContext());
85658565

85668566
// Record the semantic initializer on the outermost property wrapper.
8567-
wrappedVar->getAttachedPropertyWrappers().front()
8568-
->setSemanticInit(initializer);
8567+
wrappedVar->getOutermostAttachedPropertyWrapper()->setSemanticInit(
8568+
initializer);
85698569

85708570
// If this is a wrapped parameter, we're done.
85718571
if (isa<ParamDecl>(wrappedVar))
@@ -8983,7 +8983,7 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
89838983
return target;
89848984
} else if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
89858985
// Get the outermost wrapper type from the solution
8986-
auto outermostWrapper = wrappedVar->getAttachedPropertyWrappers().front();
8986+
auto outermostWrapper = wrappedVar->getOutermostAttachedPropertyWrapper();
89878987
auto backingType = solution.simplifyType(
89888988
solution.getType(outermostWrapper->getTypeExpr()));
89898989

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->getOutermostAttachedPropertyWrapper();
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

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3568,7 +3568,7 @@ bool InvalidProjectedValueArgument::diagnoseAsError() {
35683568
if (!param->hasAttachedPropertyWrapper()) {
35693569
param->diagnose(diag::property_wrapper_param_no_wrapper, param->getName());
35703570
} else if (!param->hasImplicitPropertyWrapper() &&
3571-
param->getAttachedPropertyWrappers().front()->hasArgs()) {
3571+
param->getOutermostAttachedPropertyWrapper()->hasArgs()) {
35723572
param->diagnose(diag::property_wrapper_param_attr_arg);
35733573
} else {
35743574
Type backingType;

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9989,7 +9989,7 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
99899989
wrappedValueType = createTypeVariable(getConstraintLocator(paramDecl),
99909990
TVO_CanBindToHole | TVO_CanBindToLValue);
99919991
} else {
9992-
auto *wrapperAttr = paramDecl->getAttachedPropertyWrappers().front();
9992+
auto *wrapperAttr = paramDecl->getOutermostAttachedPropertyWrapper();
99939993
auto wrapperType = paramDecl->getAttachedPropertyWrapperType(0);
99949994
backingType = replaceInferableTypesWithTypeVars(
99959995
wrapperType, getConstraintLocator(wrapperAttr->getTypeRepr()));

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6327,9 +6327,9 @@ void ConstraintSystem::diagnoseFailureFor(SolutionApplicationTarget target) {
63276327
DE.diagnose(expr->getLoc(), diag::type_of_expression_is_ambiguous)
63286328
.highlight(expr->getSourceRange());
63296329
} else if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
6330-
auto *wrapper = wrappedVar->getAttachedPropertyWrappers().back();
6330+
auto *outerWrapper = wrappedVar->getOutermostAttachedPropertyWrapper();
63316331
Type propertyType = wrappedVar->getInterfaceType();
6332-
Type wrapperType = wrapper->getType();
6332+
Type wrapperType = outerWrapper->getType();
63336333

63346334
// Emit the property wrapper fallback diagnostic
63356335
wrappedVar->diagnose(diag::property_wrapper_incompatible_property,

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)