Skip to content

Commit 0384700

Browse files
authored
Merge pull request #25878 from xedin/access-member-on-wrapper-type-diagnostic-5.1
[5.1][Diagnostics] Add property wrapper diagnostic for unnecessary $/'_' i…
2 parents 8eb0377 + 68026e9 commit 0384700

File tree

10 files changed

+287
-66
lines changed

10 files changed

+287
-66
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5148,6 +5148,10 @@ class VarDecl : public AbstractStorageDecl {
51485148
/// bound generic version.
51495149
VarDecl *getPropertyWrapperBackingProperty() const;
51505150

5151+
/// Retreive the storage wrapper for a property that has an attached
5152+
/// property wrapper.
5153+
VarDecl *getPropertyWrapperStorageWrapper() const;
5154+
51515155
/// Whether this is a property with a property wrapper that was initialized
51525156
/// via a value of the original type, e.g.,
51535157
///

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -981,10 +981,6 @@ ERROR(missing_address_of,none,
981981
ERROR(missing_address_of_yield,none,
982982
"yielding mutable value of type %0 requires explicit '&'",
983983
(Type))
984-
ERROR(extraneous_property_wrapper_unwrap,none,
985-
"property %0 will be unwrapped to value of type %1, use '_' to refer to "
986-
"wrapper type %2",
987-
(DeclName, Type, Type))
988984
ERROR(extraneous_address_of,none,
989985
"use of extraneous '&'",
990986
())
@@ -999,6 +995,14 @@ ERROR(cannot_pass_inout_arg_to_subscript,none,
999995
"'withUnsafeMutablePointer' to explicitly convert argument "
1000996
"to a pointer", ())
1001997

998+
ERROR(incorrect_property_wrapper_reference,none,
999+
"cannot convert value %0 of type %1 to expected type %2, "
1000+
"use %select{wrapper| wrapped value}3 instead",
1001+
(Identifier, Type, Type, bool))
1002+
ERROR(incorrect_property_wrapper_reference_member,none,
1003+
"referencing %0 %1 requires %select{wrapper|wrapped value of type}2 %3",
1004+
(DescriptiveDeclKind, DeclName, bool, Type))
1005+
10021006
ERROR(missing_init_on_metatype_initialization,none,
10031007
"initializing from a metatype value must reference 'init' explicitly",
10041008
())

lib/AST/Decl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5454,6 +5454,10 @@ VarDecl *VarDecl::getPropertyWrapperBackingProperty() const {
54545454
return getPropertyWrapperBackingPropertyInfo().backingVar;
54555455
}
54565456

5457+
VarDecl *VarDecl::getPropertyWrapperStorageWrapper() const {
5458+
return getPropertyWrapperBackingPropertyInfo().storageWrapperVar;
5459+
}
5460+
54575461
static bool propertyWrapperInitializedViaInitialValue(
54585462
const VarDecl *var, bool checkDefaultInit) {
54595463
auto customAttrs = var->getAttachedPropertyWrappers();

lib/Sema/CSDiagnostics.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,11 +1721,39 @@ bool MissingCallFailure::diagnoseAsError() {
17211721
return true;
17221722
}
17231723

1724+
bool ExtraneousPropertyWrapperUnwrapFailure::diagnoseAsError() {
1725+
auto loc = getAnchor()->getLoc();
1726+
auto newPrefix = usingStorageWrapper() ? "$" : "_";
1727+
1728+
if (auto *member = getReferencedMember()) {
1729+
emitDiagnostic(loc, diag::incorrect_property_wrapper_reference_member,
1730+
member->getDescriptiveKind(), member->getFullName(), false,
1731+
getToType())
1732+
.fixItInsert(loc, newPrefix);
1733+
return true;
1734+
}
1735+
1736+
emitDiagnostic(loc, diag::incorrect_property_wrapper_reference,
1737+
getPropertyName(), getFromType(), getToType(), false)
1738+
.fixItInsert(loc, newPrefix);
1739+
return true;
1740+
}
1741+
17241742
bool MissingPropertyWrapperUnwrapFailure::diagnoseAsError() {
1725-
emitDiagnostic(getAnchor()->getLoc(),
1726-
diag::extraneous_property_wrapper_unwrap, getPropertyName(),
1727-
getFromType(), getToType())
1728-
.fixItInsert(getAnchor()->getLoc(), "_");
1743+
auto loc = getAnchor()->getLoc();
1744+
auto endLoc = getAnchor()->getLoc().getAdvancedLoc(1);
1745+
1746+
if (auto *member = getReferencedMember()) {
1747+
emitDiagnostic(loc, diag::incorrect_property_wrapper_reference_member,
1748+
member->getDescriptiveKind(), member->getFullName(), true,
1749+
getToType())
1750+
.fixItRemoveChars(loc, endLoc);
1751+
return true;
1752+
}
1753+
1754+
emitDiagnostic(loc, diag::incorrect_property_wrapper_reference,
1755+
getPropertyName(), getFromType(), getToType(), true)
1756+
.fixItRemoveChars(loc, endLoc);
17291757
return true;
17301758
}
17311759

lib/Sema/CSDiagnostics.h

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class FailureDiagnostic {
119119
return None;
120120
}
121121

122-
ValueDecl *getResolvedMemberRef(UnresolvedDotExpr *member) {
122+
ValueDecl *getResolvedMemberRef(UnresolvedDotExpr *member) const {
123123
auto locator = CS.getConstraintLocator(member, ConstraintLocator::Member);
124124
return CS.findResolvedMemberRef(locator);
125125
}
@@ -759,20 +759,57 @@ class MissingCallFailure final : public FailureDiagnostic {
759759
bool diagnoseAsError() override;
760760
};
761761

762-
class MissingPropertyWrapperUnwrapFailure final : public ContextualFailure {
763-
DeclName PropertyName;
762+
class PropertyWrapperReferenceFailure : public ContextualFailure {
763+
VarDecl *Property;
764+
bool UsingStorageWrapper;
764765

766+
public:
767+
PropertyWrapperReferenceFailure(Expr *root, ConstraintSystem &cs,
768+
VarDecl *property, bool usingStorageWrapper,
769+
Type base, Type wrapper,
770+
ConstraintLocator *locator)
771+
: ContextualFailure(root, cs, base, wrapper, locator), Property(property),
772+
UsingStorageWrapper(usingStorageWrapper) {}
773+
774+
VarDecl *getProperty() const { return Property; }
775+
776+
Identifier getPropertyName() const { return Property->getName(); }
777+
778+
bool usingStorageWrapper() const { return UsingStorageWrapper; }
779+
780+
ValueDecl *getReferencedMember() const {
781+
auto *locator = getLocator();
782+
if (auto overload = getOverloadChoiceIfAvailable(locator))
783+
return overload->choice.getDeclOrNull();
784+
return nullptr;
785+
}
786+
};
787+
788+
class ExtraneousPropertyWrapperUnwrapFailure final
789+
: public PropertyWrapperReferenceFailure {
790+
public:
791+
ExtraneousPropertyWrapperUnwrapFailure(Expr *root, ConstraintSystem &cs,
792+
VarDecl *property,
793+
bool usingStorageWrapper, Type base,
794+
Type wrapper,
795+
ConstraintLocator *locator)
796+
: PropertyWrapperReferenceFailure(root, cs, property, usingStorageWrapper,
797+
base, wrapper, locator) {}
798+
799+
bool diagnoseAsError() override;
800+
};
801+
802+
class MissingPropertyWrapperUnwrapFailure final
803+
: public PropertyWrapperReferenceFailure {
765804
public:
766805
MissingPropertyWrapperUnwrapFailure(Expr *root, ConstraintSystem &cs,
767-
DeclName propertyName, Type base,
806+
VarDecl *property,
807+
bool usingStorageWrapper, Type base,
768808
Type wrapper, ConstraintLocator *locator)
769-
: ContextualFailure(root, cs, base, wrapper, locator),
770-
PropertyName(propertyName) {}
809+
: PropertyWrapperReferenceFailure(root, cs, property, usingStorageWrapper,
810+
base, wrapper, locator) {}
771811

772812
bool diagnoseAsError() override;
773-
774-
private:
775-
DeclName getPropertyName() const { return PropertyName; }
776813
};
777814

778815
class SubscriptMisuseFailure final : public FailureDiagnostic {

lib/Sema/CSFix.cpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,19 +260,36 @@ InsertExplicitCall *InsertExplicitCall::create(ConstraintSystem &cs,
260260
return new (cs.getAllocator()) InsertExplicitCall(cs, locator);
261261
}
262262

263-
bool InsertPropertyWrapperUnwrap::diagnose(Expr *root, bool asNote) const {
263+
bool UsePropertyWrapper::diagnose(Expr *root, bool asNote) const {
264+
auto &cs = getConstraintSystem();
265+
auto failure = ExtraneousPropertyWrapperUnwrapFailure(
266+
root, cs, Wrapped, UsingStorageWrapper, Base, Wrapper, getLocator());
267+
return failure.diagnose(asNote);
268+
}
269+
270+
UsePropertyWrapper *UsePropertyWrapper::create(ConstraintSystem &cs,
271+
VarDecl *wrapped,
272+
bool usingStorageWrapper,
273+
Type base, Type wrapper,
274+
ConstraintLocator *locator) {
275+
return new (cs.getAllocator()) UsePropertyWrapper(
276+
cs, wrapped, usingStorageWrapper, base, wrapper, locator);
277+
}
278+
279+
bool UseWrappedValue::diagnose(Expr *root, bool asNote) const {
280+
auto &cs = getConstraintSystem();
264281
auto failure = MissingPropertyWrapperUnwrapFailure(
265-
root, getConstraintSystem(), getPropertyName(), getBase(), getWrapper(),
282+
root, cs, PropertyWrapper, usingStorageWrapper(), Base, Wrapper,
266283
getLocator());
267284
return failure.diagnose(asNote);
268285
}
269286

270-
InsertPropertyWrapperUnwrap *
271-
InsertPropertyWrapperUnwrap::create(ConstraintSystem &cs, DeclName propertyName,
272-
Type base, Type wrapper,
273-
ConstraintLocator *locator) {
287+
UseWrappedValue *UseWrappedValue::create(ConstraintSystem &cs,
288+
VarDecl *propertyWrapper, Type base,
289+
Type wrapper,
290+
ConstraintLocator *locator) {
274291
return new (cs.getAllocator())
275-
InsertPropertyWrapperUnwrap(cs, propertyName, base, wrapper, locator);
292+
UseWrappedValue(cs, propertyWrapper, base, wrapper, locator);
276293
}
277294

278295
bool UseSubscriptOperator::diagnose(Expr *root, bool asNote) const {

lib/Sema/CSFix.h

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,13 @@ enum class FixKind : uint8_t {
100100
/// Add explicit `()` at the end of function or member to call it.
101101
InsertCall,
102102

103-
/// Add one or more property unwrap operators ('$')
104-
InsertPropertyWrapperUnwrap,
103+
/// Add '$' or '_' to refer to the property wrapper or storage instead
104+
/// of the wrapped property type.
105+
UsePropertyWrapper,
106+
107+
/// Remove '$' or '_' to refer to the wrapped property type instead of
108+
/// the storage or property wrapper.
109+
UseWrappedValue,
105110

106111
/// Instead of spelling out `subscript` directly, use subscript operator.
107112
UseSubscriptOperator,
@@ -566,32 +571,56 @@ class InsertExplicitCall final : public ConstraintFix {
566571
ConstraintLocator *locator);
567572
};
568573

569-
class InsertPropertyWrapperUnwrap final : public ConstraintFix {
570-
DeclName PropertyName;
574+
class UsePropertyWrapper final : public ConstraintFix {
575+
VarDecl *Wrapped;
576+
bool UsingStorageWrapper;
571577
Type Base;
572578
Type Wrapper;
573579

574-
InsertPropertyWrapperUnwrap(ConstraintSystem &cs, DeclName propertyName,
575-
Type base, Type wrapper,
576-
ConstraintLocator *locator)
577-
: ConstraintFix(cs, FixKind::InsertPropertyWrapperUnwrap, locator),
578-
PropertyName(propertyName), Base(base), Wrapper(wrapper) {}
580+
UsePropertyWrapper(ConstraintSystem &cs, VarDecl *wrapped,
581+
bool usingStorageWrapper, Type base, Type wrapper,
582+
ConstraintLocator *locator)
583+
: ConstraintFix(cs, FixKind::UsePropertyWrapper, locator),
584+
Wrapped(wrapped), UsingStorageWrapper(usingStorageWrapper), Base(base),
585+
Wrapper(wrapper) {}
579586

580587
public:
581588
std::string getName() const override {
582-
return "insert a $ to unwrap the property wrapper";
589+
return "insert '$' or '_' to use property wrapper type instead of wrapped type";
590+
}
591+
592+
bool diagnose(Expr *root, bool asNote = false) const override;
593+
594+
static UsePropertyWrapper *create(ConstraintSystem &cs, VarDecl *wrapped,
595+
bool usingStorageWrapper, Type base,
596+
Type wrapper, ConstraintLocator *locator);
597+
};
598+
599+
class UseWrappedValue final : public ConstraintFix {
600+
VarDecl *PropertyWrapper;
601+
Type Base;
602+
Type Wrapper;
603+
604+
UseWrappedValue(ConstraintSystem &cs, VarDecl *propertyWrapper, Type base,
605+
Type wrapper, ConstraintLocator *locator)
606+
: ConstraintFix(cs, FixKind::UseWrappedValue, locator),
607+
PropertyWrapper(propertyWrapper), Base(base), Wrapper(wrapper) {}
608+
609+
bool usingStorageWrapper() const {
610+
auto nameStr = PropertyWrapper->getName().str();
611+
return !nameStr.startswith("_");
583612
}
584613

585-
DeclName getPropertyName() const { return PropertyName; }
586-
Type getBase() const { return Base; }
587-
Type getWrapper() const { return Wrapper; }
614+
public:
615+
std::string getName() const override {
616+
return "remove '$' or _ to use wrapped type instead of wrapper type";
617+
}
588618

589619
bool diagnose(Expr *root, bool asNote = false) const override;
590620

591-
static InsertPropertyWrapperUnwrap *create(ConstraintSystem &cs,
592-
DeclName propertyName, Type base,
593-
Type wrapper,
594-
ConstraintLocator *locator);
621+
static UseWrappedValue *create(ConstraintSystem &cs, VarDecl *propertyWrapper,
622+
Type base, Type wrapper,
623+
ConstraintLocator *locator);
595624
};
596625

597626
class UseSubscriptOperator final : public ConstraintFix {

lib/Sema/CSSimplify.cpp

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4741,31 +4741,61 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
47414741
return SolutionKind::Solved;
47424742
}
47434743

4744-
auto solveWithNewBaseOrName = [&](Type baseType,
4745-
DeclName memberName) -> SolutionKind {
4744+
auto solveWithNewBaseOrName = [&](Type baseType, DeclName memberName,
4745+
bool allowFixes = true) -> SolutionKind {
47464746
// Let's re-enable fixes for this member, because
47474747
// the base or member name has been changed.
4748-
MissingMembers.remove(locator);
4748+
if (allowFixes)
4749+
MissingMembers.remove(locator);
47494750
return simplifyMemberConstraint(kind, baseType, memberName, memberTy,
47504751
useDC, functionRefKind, outerAlternatives,
47514752
flags, locatorB);
47524753
};
47534754

47544755
// Check if any property wrappers on the base of the member lookup have
4755-
// mactching members that we can fall back to.
4756+
// matching members that we can fall back to, or if the type wraps any
4757+
// properties that have matching members.
47564758
if (auto dotExpr =
47574759
dyn_cast_or_null<UnresolvedDotExpr>(locator->getAnchor())) {
47584760
auto baseExpr = dotExpr->getBase();
4759-
auto resolvedOverload = findSelectedOverloadFor(baseExpr);
4760-
if (auto wrappedProperty =
4761-
getPropertyWrapperInformation(resolvedOverload)) {
4762-
auto wrapperTy = wrappedProperty->second;
4763-
auto result = solveWithNewBaseOrName(wrapperTy, member);
4764-
if (result == SolutionKind::Solved) {
4765-
auto *fix = InsertPropertyWrapperUnwrap::create(
4766-
*this, wrappedProperty->first->getFullName(), baseTy, wrapperTy,
4767-
locator);
4768-
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
4761+
4762+
if (auto resolvedOverload = findSelectedOverloadFor(baseExpr)) {
4763+
if (auto storageWrapper =
4764+
getStorageWrapperInformation(resolvedOverload)) {
4765+
auto wrapperTy = storageWrapper->second;
4766+
auto result =
4767+
solveWithNewBaseOrName(wrapperTy, member, /*allowFixes=*/false);
4768+
if (result == SolutionKind::Solved) {
4769+
auto *fix = UsePropertyWrapper::create(*this, storageWrapper->first,
4770+
/*usingStorageWrapper=*/true,
4771+
baseTy, wrapperTy, locator);
4772+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
4773+
}
4774+
}
4775+
4776+
if (auto wrapper = getPropertyWrapperInformation(resolvedOverload)) {
4777+
auto wrapperTy = wrapper->second;
4778+
auto result =
4779+
solveWithNewBaseOrName(wrapperTy, member, /*allowFixes=*/false);
4780+
if (result == SolutionKind::Solved) {
4781+
auto *fix = UsePropertyWrapper::create(
4782+
*this, wrapper->first,
4783+
/*usingStorageWrappeer=*/false, baseTy, wrapperTy, locator);
4784+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
4785+
}
4786+
}
4787+
4788+
if (auto wrappedProperty =
4789+
getWrappedPropertyInformation(resolvedOverload)) {
4790+
auto wrappedTy = wrappedProperty->second;
4791+
auto result =
4792+
solveWithNewBaseOrName(wrappedTy, member, /*allowFixes=*/false);
4793+
4794+
if (result == SolutionKind::Solved) {
4795+
auto *fix = UseWrappedValue::create(*this, wrappedProperty->first,
4796+
baseTy, wrappedTy, locator);
4797+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
4798+
}
47694799
}
47704800
}
47714801
}
@@ -6716,7 +6746,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
67166746
case FixKind::TreatKeyPathSubscriptIndexAsHashable:
67176747
case FixKind::AllowInvalidRefInKeyPath:
67186748
case FixKind::ExplicitlySpecifyGenericArguments:
6719-
case FixKind::InsertPropertyWrapperUnwrap:
6749+
case FixKind::UsePropertyWrapper:
6750+
case FixKind::UseWrappedValue:
67206751
llvm_unreachable("handled elsewhere");
67216752
}
67226753

0 commit comments

Comments
 (0)