Skip to content

Commit a803cb5

Browse files
authored
Merge pull request #60384 from xedin/rdar-94506352-aux-vars
[CSClosure] Add support for projected/wrapper values
2 parents b62dede + 5ee5a22 commit a803cb5

File tree

8 files changed

+122
-8
lines changed

8 files changed

+122
-8
lines changed

include/swift/AST/Decl.h

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

5450+
/// Retrieve the outermost property wrapper attribute associated with
5451+
/// this declaration. For example:
5452+
///
5453+
/// \code
5454+
/// @A @B @C var <name>: Bool = ...
5455+
/// \endcode
5456+
///
5457+
/// The outermost attribute in this case is `@A` and it has
5458+
/// complete wrapper type `A<B<C<Bool>>>`.
5459+
CustomAttr *getOutermostAttachedPropertyWrapper() const {
5460+
auto wrappers = getAttachedPropertyWrappers();
5461+
return wrappers.empty() ? nullptr : wrappers.front();
5462+
}
5463+
54505464
/// Whether this property has any attached property wrappers.
54515465
bool hasAttachedPropertyWrapper() const;
54525466

lib/AST/Decl.cpp

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

66026602
// Wrappers with attribute arguments are always implementation-detail.
6603-
if (getAttachedPropertyWrappers().front()->hasArgs())
6603+
if (getOutermostAttachedPropertyWrapper()->hasArgs())
66046604
return false;
66056605

66066606
auto wrapperInfo = getAttachedPropertyWrapperTypeInfo(0);

lib/Sema/CSApply.cpp

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

85808580
// Record the semantic initializer on the outermost property wrapper.
8581-
wrappedVar->getAttachedPropertyWrappers().front()
8582-
->setSemanticInit(initializer);
8581+
wrappedVar->getOutermostAttachedPropertyWrapper()->setSemanticInit(
8582+
initializer);
85838583

85848584
// If this is a wrapped parameter, we're done.
85858585
if (isa<ParamDecl>(wrappedVar))
@@ -8997,7 +8997,7 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
89978997
return target;
89988998
} else if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
89998999
// Get the outermost wrapper type from the solution
9000-
auto outermostWrapper = wrappedVar->getAttachedPropertyWrappers().front();
9000+
auto outermostWrapper = wrappedVar->getOutermostAttachedPropertyWrapper();
90019001
auto backingType = solution.simplifyType(
90029002
solution.getType(outermostWrapper->getTypeExpr()));
90039003

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

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3615,7 +3615,7 @@ bool InvalidProjectedValueArgument::diagnoseAsError() {
36153615
if (!param->hasAttachedPropertyWrapper()) {
36163616
param->diagnose(diag::property_wrapper_param_no_wrapper, param->getName());
36173617
} else if (!param->hasImplicitPropertyWrapper() &&
3618-
param->getAttachedPropertyWrappers().front()->hasArgs()) {
3618+
param->getOutermostAttachedPropertyWrapper()->hasArgs()) {
36193619
param->diagnose(diag::property_wrapper_param_attr_arg);
36203620
} else {
36213621
Type backingType;

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9972,7 +9972,7 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
99729972
wrappedValueType = createTypeVariable(getConstraintLocator(paramDecl),
99739973
TVO_CanBindToHole | TVO_CanBindToLValue);
99749974
} else {
9975-
auto *wrapperAttr = paramDecl->getAttachedPropertyWrappers().front();
9975+
auto *wrapperAttr = paramDecl->getOutermostAttachedPropertyWrapper();
99769976
auto wrapperType = paramDecl->getAttachedPropertyWrapperType(0);
99779977
backingType = replaceInferableTypesWithTypeVars(
99789978
wrapperType, getConstraintLocator(wrapperAttr->getTypeRepr()));

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6433,9 +6433,9 @@ void ConstraintSystem::diagnoseFailureFor(SolutionApplicationTarget target) {
64336433
DE.diagnose(expr->getLoc(), diag::type_of_expression_is_ambiguous)
64346434
.highlight(expr->getSourceRange());
64356435
} else if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
6436-
auto *wrapper = wrappedVar->getAttachedPropertyWrappers().back();
6436+
auto *outerWrapper = wrappedVar->getOutermostAttachedPropertyWrapper();
64376437
Type propertyType = wrappedVar->getInterfaceType();
6438-
Type wrapperType = wrapper->getType();
6438+
Type wrapperType = outerWrapper->getType();
64396439

64406440
// Emit the property wrapper fallback diagnostic
64416441
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)