Skip to content

Commit e4d4c0b

Browse files
[Sema] Moving detection of fix base type for optional member to attempt fix method
1 parent d954b84 commit e4d4c0b

File tree

3 files changed

+96
-99
lines changed

3 files changed

+96
-99
lines changed

include/swift/Sema/CSFix.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class ConstraintLocator;
4646
class ConstraintLocatorBuilder;
4747
enum class ConversionRestrictionKind;
4848
class Solution;
49+
struct MemberLookupResult;
4950

5051
/// Describes the kind of fix to apply to the given constraint before
5152
/// visiting it.
@@ -2147,6 +2148,10 @@ class AllowRefToInvalidDecl final : public ConstraintFix {
21472148
ConstraintLocator *locator);
21482149
};
21492150

2151+
/// Diagnose if the base type is optional, we're referring to a nominal
2152+
/// type member via the dot syntax and the member name matches
2153+
/// Optional<T>.{member} or a .none member inferred as non-optional static
2154+
/// member e.g. let _ : Foo? = .none where Foo has a static member none.
21502155
class SpecifyBaseTypeForOptionalUnresolvedMember final : public ConstraintFix {
21512156
SpecifyBaseTypeForOptionalUnresolvedMember(ConstraintSystem &cs,
21522157
DeclNameRef memberName,
@@ -2166,8 +2171,9 @@ class SpecifyBaseTypeForOptionalUnresolvedMember final : public ConstraintFix {
21662171
bool diagnose(const Solution &solution, bool asNote = false) const override;
21672172

21682173
static SpecifyBaseTypeForOptionalUnresolvedMember *
2169-
create(ConstraintSystem &cs, DeclNameRef memberName,
2170-
ConstraintLocator *locator);
2174+
attempt(ConstraintSystem &cs, ConstraintKind kind, Type baseTy,
2175+
DeclNameRef memberName, FunctionRefKind functionRefKind,
2176+
MemberLookupResult result, ConstraintLocator *locator);
21712177
};
21722178

21732179
} // end namespace constraints

lib/Sema/CSFix.cpp

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,9 +1682,91 @@ bool SpecifyBaseTypeForOptionalUnresolvedMember::diagnose(
16821682
}
16831683

16841684
SpecifyBaseTypeForOptionalUnresolvedMember *
1685-
SpecifyBaseTypeForOptionalUnresolvedMember::create(ConstraintSystem &cs,
1686-
DeclNameRef memberName,
1687-
ConstraintLocator *locator) {
1685+
SpecifyBaseTypeForOptionalUnresolvedMember::attempt(
1686+
ConstraintSystem &cs, ConstraintKind kind, Type baseTy,
1687+
DeclNameRef memberName, FunctionRefKind functionRefKind,
1688+
MemberLookupResult result, ConstraintLocator *locator) {
1689+
1690+
if (kind != ConstraintKind::UnresolvedValueMember)
1691+
return nullptr;
1692+
1693+
// None or only one viable candidate, there is no ambiguity.
1694+
if (result.ViableCandidates.size() <= 1)
1695+
return nullptr;
1696+
1697+
// Only diagnose those situations for static members.
1698+
if (!baseTy->is<MetatypeType>())
1699+
return nullptr;
1700+
1701+
// Don't diagnose for function members e.g. Foo? = .none(0).
1702+
if (functionRefKind != FunctionRefKind::Unapplied)
1703+
return nullptr;
1704+
1705+
Type underlyingBaseType = baseTy->getMetatypeInstanceType();
1706+
if (!underlyingBaseType->getNominalOrBoundGenericNominal())
1707+
return nullptr;
1708+
1709+
if (!underlyingBaseType->getOptionalObjectType())
1710+
return nullptr;
1711+
1712+
auto unwrappedType = underlyingBaseType->lookThroughAllOptionalTypes();
1713+
bool allOptionalBaseCandidates = true;
1714+
auto filterViableCandidates =
1715+
[&](SmallVector<OverloadChoice, 4> &candidates,
1716+
SmallVector<OverloadChoice, 4> &viableCandidates,
1717+
bool &allOptionalBase) {
1718+
for (OverloadChoice choice : candidates) {
1719+
if (!choice.isDecl())
1720+
continue;
1721+
1722+
auto memberDecl = choice.getDecl();
1723+
if (isa<FuncDecl>(memberDecl))
1724+
continue;
1725+
if (memberDecl->isInstanceMember())
1726+
continue;
1727+
1728+
allOptionalBase &= bool(choice.getBaseType()
1729+
->getMetatypeInstanceType()
1730+
->getOptionalObjectType());
1731+
1732+
if (auto EED = dyn_cast<EnumElementDecl>(memberDecl)) {
1733+
if (!EED->hasAssociatedValues())
1734+
viableCandidates.push_back(choice);
1735+
} else if (auto VD = dyn_cast<VarDecl>(memberDecl)) {
1736+
if (unwrappedType->hasTypeVariable() ||
1737+
VD->getInterfaceType()->isEqual(unwrappedType))
1738+
viableCandidates.push_back(choice);
1739+
}
1740+
}
1741+
};
1742+
1743+
SmallVector<OverloadChoice, 4> viableCandidates;
1744+
filterViableCandidates(result.ViableCandidates, viableCandidates,
1745+
allOptionalBaseCandidates);
1746+
1747+
// Also none or only one viable candidate after filtering candidates, there is
1748+
// no ambiguity.
1749+
if (viableCandidates.size() <= 1)
1750+
return nullptr;
1751+
1752+
// Right now, name lookup only unwraps a single layer of optionality, which
1753+
// for cases where base type is a multi-optional type e.g. Foo?? it only
1754+
// finds optional base candidates. To produce the correct warning we perform
1755+
// an extra lookup on unwrapped type.
1756+
if (!allOptionalBaseCandidates)
1757+
return new (cs.getAllocator())
1758+
SpecifyBaseTypeForOptionalUnresolvedMember(cs, memberName, locator);
1759+
1760+
MemberLookupResult unwrappedResult =
1761+
cs.performMemberLookup(kind, memberName, MetatypeType::get(unwrappedType),
1762+
functionRefKind, locator,
1763+
/*includeInaccessibleMembers*/ false);
1764+
SmallVector<OverloadChoice, 4> unwrappedViableCandidates;
1765+
filterViableCandidates(unwrappedResult.ViableCandidates,
1766+
unwrappedViableCandidates, allOptionalBaseCandidates);
1767+
if (unwrappedViableCandidates.empty())
1768+
return nullptr;
1769+
16881770
return new (cs.getAllocator())
16891771
SpecifyBaseTypeForOptionalUnresolvedMember(cs, memberName, locator);
16901772
}

lib/Sema/CSSimplify.cpp

Lines changed: 3 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -7109,95 +7109,6 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
71097109
return nullptr;
71107110
}
71117111

7112-
/// Diagnose if the base type is optional, we're referring to a nominal
7113-
/// type member via the dot syntax and the member name matches
7114-
/// Optional<T>.{member} or a .none member inferred as non-optional static
7115-
/// member e.g. let _ : Foo? = .none where Foo has a static member none.
7116-
static bool attemptUnresolvedMemberFix(ConstraintSystem &cs,
7117-
ConstraintKind kind, Type baseTy,
7118-
DeclNameRef member,
7119-
FunctionRefKind functionRefKind,
7120-
ConstraintLocator *locator,
7121-
MemberLookupResult result) {
7122-
7123-
if (kind != ConstraintKind::UnresolvedValueMember)
7124-
return false;
7125-
7126-
// None or only one viable candidate, there is no ambiguity.
7127-
if (result.ViableCandidates.size() <= 1)
7128-
return false;
7129-
7130-
// Only diagnose those situations for static members.
7131-
if (!baseTy->is<MetatypeType>())
7132-
return false;
7133-
7134-
// Don't diagnose for function members e.g. Foo? = .none(0).
7135-
if (functionRefKind != FunctionRefKind::Unapplied)
7136-
return false;
7137-
7138-
Type underlyingBaseType = baseTy->getMetatypeInstanceType();
7139-
if (!underlyingBaseType->getNominalOrBoundGenericNominal())
7140-
return false;
7141-
7142-
if (!underlyingBaseType->getOptionalObjectType())
7143-
return false;
7144-
7145-
auto unwrappedType = underlyingBaseType->lookThroughAllOptionalTypes();
7146-
bool allOptionalBaseCandidates = true;
7147-
auto filterViableCandidates =
7148-
[&](SmallVector<OverloadChoice, 4> &candidates,
7149-
SmallVector<OverloadChoice, 4> &viableCandidates,
7150-
bool &allOptionalBase) {
7151-
for (OverloadChoice choice : candidates) {
7152-
if (!choice.isDecl())
7153-
continue;
7154-
7155-
auto memberDecl = choice.getDecl();
7156-
if (isa<FuncDecl>(memberDecl))
7157-
continue;
7158-
if (memberDecl->isInstanceMember())
7159-
continue;
7160-
7161-
allOptionalBase &= bool(choice.getBaseType()
7162-
->getMetatypeInstanceType()
7163-
->getOptionalObjectType());
7164-
7165-
if (auto EED = dyn_cast<EnumElementDecl>(memberDecl)) {
7166-
if (!EED->hasAssociatedValues())
7167-
viableCandidates.push_back(choice);
7168-
} else if (auto VD = dyn_cast<VarDecl>(memberDecl)) {
7169-
if (unwrappedType->hasTypeVariable() ||
7170-
VD->getInterfaceType()->isEqual(unwrappedType))
7171-
viableCandidates.push_back(choice);
7172-
}
7173-
}
7174-
};
7175-
7176-
SmallVector<OverloadChoice, 4> viableCandidates;
7177-
filterViableCandidates(result.ViableCandidates, viableCandidates,
7178-
allOptionalBaseCandidates);
7179-
7180-
// Also none or only one viable candidate after filtering candidates, there is
7181-
// no ambiguity.
7182-
if (viableCandidates.size() <= 1)
7183-
return false;
7184-
7185-
// Right now, name lookup only unwraps a single layer of optionality, which
7186-
// for cases where base type is a multi-optional type e.g. Foo?? it only
7187-
// finds optional base candidates. To produce the correct warning we perform
7188-
// an extra lookup on unwrapped type.
7189-
if (!allOptionalBaseCandidates)
7190-
return true;
7191-
7192-
MemberLookupResult unwrappedResult = cs.performMemberLookup(
7193-
kind, member, MetatypeType::get(unwrappedType), functionRefKind, locator,
7194-
/*includeInaccessibleMembers*/ false);
7195-
SmallVector<OverloadChoice, 4> unwrappedViableCandidates;
7196-
filterViableCandidates(unwrappedResult.ViableCandidates,
7197-
unwrappedViableCandidates, allOptionalBaseCandidates);
7198-
return !unwrappedViableCandidates.empty();
7199-
}
7200-
72017112
ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
72027113
ConstraintKind kind, Type baseTy, DeclNameRef member, Type memberTy,
72037114
DeclContext *useDC, FunctionRefKind functionRefKind,
@@ -7397,11 +7308,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
73977308
// }
73987309
//
73997310
// let _: Foo? = .none // Although base is inferred as Optional.none
7400-
// it could be also.
7401-
if (attemptUnresolvedMemberFix(*this, kind, baseObjTy, member,
7402-
functionRefKind, locator, result)) {
7403-
auto *fix = SpecifyBaseTypeForOptionalUnresolvedMember::create(
7404-
*this, member, locator);
7311+
// it could be also Foo.none.
7312+
if (auto *fix = SpecifyBaseTypeForOptionalUnresolvedMember::attempt(
7313+
*this, kind, baseObjTy, member, functionRefKind, result, locator)) {
74057314
(void)recordFix(fix);
74067315
}
74077316

0 commit comments

Comments
 (0)