@@ -1555,9 +1555,9 @@ bool AssignmentFailure::diagnoseAsError() {
1555
1555
1556
1556
// Walk through the destination expression, resolving what the problem is. If
1557
1557
// we find a node in the lvalue path that is problematic, this returns it.
1558
- auto immInfo = resolveImmutableBase (DestExpr) ;
1559
-
1560
- Optional<OverloadChoice> choice = immInfo. second ;
1558
+ Expr *immutableExpr ;
1559
+ Optional<OverloadChoice> choice;
1560
+ std::tie (immutableExpr, choice) = resolveImmutableBase (DestExpr) ;
1561
1561
1562
1562
// Attempt diagnostics based on the overload choice.
1563
1563
if (choice.hasValue ()) {
@@ -1571,17 +1571,17 @@ bool AssignmentFailure::diagnoseAsError() {
1571
1571
1572
1572
if (!choice->isDecl ()) {
1573
1573
if (choice->getKind () == OverloadChoiceKind::KeyPathApplication &&
1574
- !isa<ApplyExpr>(immInfo. first )) {
1574
+ !isa<ApplyExpr>(immutableExpr )) {
1575
1575
std::string message = " key path is read-only" ;
1576
- if (auto *SE = dyn_cast<SubscriptExpr>(immInfo. first )) {
1576
+ if (auto *SE = dyn_cast<SubscriptExpr>(immutableExpr )) {
1577
1577
if (auto *DRE = dyn_cast<DeclRefExpr>(getKeyPathArgument (SE))) {
1578
1578
auto identifier = DRE->getDecl ()->getBaseName ().getIdentifier ();
1579
1579
message =
1580
1580
" '" + identifier.str ().str () + " ' is a read-only key path" ;
1581
1581
}
1582
1582
}
1583
1583
emitDiagnostic (Loc, DeclDiagnostic, message)
1584
- .highlight (immInfo. first ->getSourceRange ());
1584
+ .highlight (immutableExpr ->getSourceRange ());
1585
1585
return true ;
1586
1586
}
1587
1587
return false ;
@@ -1595,7 +1595,7 @@ bool AssignmentFailure::diagnoseAsError() {
1595
1595
message += VD->getName ().str ().str ();
1596
1596
message += " '" ;
1597
1597
1598
- auto type = getType (immInfo. first );
1598
+ auto type = getType (immutableExpr );
1599
1599
1600
1600
if (isKnownKeyPathType (type))
1601
1601
message += " is read-only" ;
@@ -1614,26 +1614,54 @@ bool AssignmentFailure::diagnoseAsError() {
1614
1614
}
1615
1615
1616
1616
emitDiagnostic (Loc, DeclDiagnostic, message)
1617
- .highlight (immInfo. first ->getSourceRange ());
1617
+ .highlight (immutableExpr ->getSourceRange ());
1618
1618
1619
- // If there is a masked instance variable of the same type, emit a
1620
- // note to fixit prepend a 'self.'.
1619
+ // If there is a masked property of the same type, emit a
1620
+ // note to fixit prepend a 'self.' or 'Type.' .
1621
1621
if (auto typeContext = DC->getInnermostTypeContext ()) {
1622
- UnqualifiedLookup lookup (VD->getFullName (), typeContext);
1623
- for (auto &result : lookup.Results ) {
1624
- const VarDecl *typeVar = dyn_cast<VarDecl>(result.getValueDecl ());
1625
- if (typeVar && typeVar != VD && typeVar->isSettable (DC) &&
1626
- typeVar->isSetterAccessibleFrom (DC) &&
1627
- typeVar->getType ()->isEqual (VD->getType ())) {
1628
- // But not in its own accessor.
1629
- auto AD =
1630
- dyn_cast_or_null<AccessorDecl>(DC->getInnermostMethodContext ());
1631
- if (!AD || AD->getStorage () != typeVar) {
1632
- emitDiagnostic (Loc, diag::masked_instance_variable,
1633
- typeContext->getSelfTypeInContext ())
1634
- .fixItInsert (Loc, " self." );
1635
- }
1622
+ SmallVector<ValueDecl *, 2 > results;
1623
+ DC->lookupQualified (typeContext->getSelfNominalTypeDecl (),
1624
+ VD->getFullName (),
1625
+ NL_QualifiedDefault | NL_RemoveNonVisible, results);
1626
+
1627
+ auto foundProperty = llvm::find_if (results, [&](ValueDecl *decl) {
1628
+ // We're looking for a settable property that is the same type as the
1629
+ // var we found.
1630
+ auto *var = dyn_cast<VarDecl>(decl);
1631
+ if (!var || var == VD)
1632
+ return false ;
1633
+
1634
+ if (!var->isSettable (DC) || !var->isSetterAccessibleFrom (DC))
1635
+ return false ;
1636
+
1637
+ if (!var->getType ()->isEqual (VD->getType ()))
1638
+ return false ;
1639
+
1640
+ // Don't suggest a property if we're in one of its accessors.
1641
+ auto *methodDC = DC->getInnermostMethodContext ();
1642
+ if (auto *AD = dyn_cast_or_null<AccessorDecl>(methodDC))
1643
+ if (AD->getStorage () == var)
1644
+ return false ;
1645
+
1646
+ return true ;
1647
+ });
1648
+
1649
+ if (foundProperty != results.end ()) {
1650
+ auto startLoc = immutableExpr->getStartLoc ();
1651
+ auto *property = *foundProperty;
1652
+ auto selfTy = typeContext->getSelfTypeInContext ();
1653
+
1654
+ // If we found an instance property, suggest inserting "self.",
1655
+ // otherwise suggest "Type." for a static property.
1656
+ std::string fixItText;
1657
+ if (property->isInstanceMember ()) {
1658
+ fixItText = " self." ;
1659
+ } else {
1660
+ fixItText = selfTy->getString () + " ." ;
1636
1661
}
1662
+ emitDiagnostic (startLoc, diag::masked_mutable_property,
1663
+ fixItText, property->getDescriptiveKind (), selfTy)
1664
+ .fixItInsert (startLoc, fixItText);
1637
1665
}
1638
1666
}
1639
1667
@@ -1654,7 +1682,7 @@ bool AssignmentFailure::diagnoseAsError() {
1654
1682
message = " subscript is immutable" ;
1655
1683
1656
1684
emitDiagnostic (Loc, DeclDiagnostic, message)
1657
- .highlight (immInfo. first ->getSourceRange ());
1685
+ .highlight (immutableExpr ->getSourceRange ());
1658
1686
return true ;
1659
1687
}
1660
1688
@@ -1676,7 +1704,7 @@ bool AssignmentFailure::diagnoseAsError() {
1676
1704
message += " is not settable" ;
1677
1705
1678
1706
emitDiagnostic (Loc, diagID, message)
1679
- .highlight (immInfo. first ->getSourceRange ());
1707
+ .highlight (immutableExpr ->getSourceRange ());
1680
1708
return true ;
1681
1709
}
1682
1710
}
@@ -1686,21 +1714,21 @@ bool AssignmentFailure::diagnoseAsError() {
1686
1714
1687
1715
// If a keypath was the problem but wasn't resolved into a vardecl
1688
1716
// it is ambiguous or unable to be used for setting.
1689
- if (auto *KPE = dyn_cast_or_null<KeyPathExpr>(immInfo. first )) {
1717
+ if (auto *KPE = dyn_cast_or_null<KeyPathExpr>(immutableExpr )) {
1690
1718
emitDiagnostic (Loc, DeclDiagnostic, " immutable key path" )
1691
1719
.highlight (KPE->getSourceRange ());
1692
1720
return true ;
1693
1721
}
1694
1722
1695
- if (auto LE = dyn_cast<LiteralExpr>(immInfo. first )) {
1723
+ if (auto LE = dyn_cast<LiteralExpr>(immutableExpr )) {
1696
1724
emitDiagnostic (Loc, DeclDiagnostic, " literals are not mutable" )
1697
1725
.highlight (LE->getSourceRange ());
1698
1726
return true ;
1699
1727
}
1700
1728
1701
1729
// If the expression is the result of a call, it is an rvalue, not a mutable
1702
1730
// lvalue.
1703
- if (auto *AE = dyn_cast<ApplyExpr>(immInfo. first )) {
1731
+ if (auto *AE = dyn_cast<ApplyExpr>(immutableExpr )) {
1704
1732
// Handle literals, which are a call to the conversion function.
1705
1733
auto argsTuple =
1706
1734
dyn_cast<TupleExpr>(AE->getArg ()->getSemanticsProvidingExpr ());
@@ -1733,22 +1761,22 @@ bool AssignmentFailure::diagnoseAsError() {
1733
1761
return true ;
1734
1762
}
1735
1763
1736
- if (auto contextualType = cs.getContextualType (immInfo. first )) {
1764
+ if (auto contextualType = cs.getContextualType (immutableExpr )) {
1737
1765
Type neededType = contextualType->getInOutObjectType ();
1738
- Type actualType = getType (immInfo. first )->getInOutObjectType ();
1766
+ Type actualType = getType (immutableExpr )->getInOutObjectType ();
1739
1767
if (!neededType->isEqual (actualType)) {
1740
1768
if (DeclDiagnostic.ID != diag::cannot_pass_rvalue_inout_subelement.ID ) {
1741
1769
emitDiagnostic (Loc, DeclDiagnostic,
1742
1770
" implicit conversion from '" + actualType->getString () +
1743
1771
" ' to '" + neededType->getString () +
1744
1772
" ' requires a temporary" )
1745
- .highlight (immInfo. first ->getSourceRange ());
1773
+ .highlight (immutableExpr ->getSourceRange ());
1746
1774
}
1747
1775
return true ;
1748
1776
}
1749
1777
}
1750
1778
1751
- if (auto IE = dyn_cast<IfExpr>(immInfo. first )) {
1779
+ if (auto IE = dyn_cast<IfExpr>(immutableExpr )) {
1752
1780
emitDiagnostic (Loc, DeclDiagnostic,
1753
1781
" result of conditional operator '? :' is never mutable" )
1754
1782
.highlight (IE->getQuestionLoc ())
@@ -1757,7 +1785,7 @@ bool AssignmentFailure::diagnoseAsError() {
1757
1785
}
1758
1786
1759
1787
emitDiagnostic (Loc, TypeDiagnostic, getType (DestExpr))
1760
- .highlight (immInfo. first ->getSourceRange ());
1788
+ .highlight (immutableExpr ->getSourceRange ());
1761
1789
return true ;
1762
1790
}
1763
1791
0 commit comments