mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Sema] Improve diagnostics for witness mismatches against @objc protocols.
Simplify and improve the checking of @objc names when matching a witness to a requirement in the @objc protocol. First, don't use @objc-ness as part of the initial screening to determine whether a witness potentially matches an @objc requirement: we will only reject a potential witness when the potential witness has an explicit "@nonobjc" attribute on it. Otherwise, the presence of @objc and the corresponding Objective-C name is checked only after selecting a candidate. This more closely mirrors what we do for override checking, where we match based on the Swift names (first) and validate @objc'ness afterward. It is also a stepping stone to inferring @objc'ness and @objc names from protocol conformances. Second, when emitting a diagnostic about a missing or incorrect @objc annotation, make sure the Fix-It gets the @objc name right: this might mean adding the Objective-C name along with @objc (e.g., "@objc(fooWithString:bar:)"), adding the name to an unadorned-but-explicit "@objc" attribute, or fixing the name of an @objc attribute (e.g., "@objc(foo:bar:)" becomes @objc(fooWithString:bar:)"). Make this diagnostic an error, rather than a note on a generic "does not conform" diagnostic, so it's much easier to see the diagnostic and apply the Fix-It. Third, when emitting the warning about a non-@objc near-match for an optional @objc requirement, provide two Fix-Its: one that adds the appropriate @objc annotation (per the paragraph above), and one that adds @nonobjc to silence the warning. Part of the QoI improvements for conformances to @objc protocols, rdar://problem/25159872.
This commit is contained in:
@@ -1039,6 +1039,16 @@ Type ConstraintSystem::replaceSelfTypeInArchetype(ArchetypeType *archetype) {
|
||||
return archetype;
|
||||
}
|
||||
|
||||
/// Determine whether the given locator is for a witness or requirement.
|
||||
static bool isRequirementOrWitnesss(const ConstraintLocatorBuilder &locator) {
|
||||
if (auto last = locator.last()) {
|
||||
return last->getKind() == ConstraintLocator::Requirement ||
|
||||
last->getKind() == ConstraintLocator::Witness;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<Type, Type>
|
||||
ConstraintSystem::getTypeOfMemberReference(
|
||||
Type baseTy, ValueDecl *value,
|
||||
@@ -1237,10 +1247,14 @@ ConstraintSystem::getTypeOfMemberReference(
|
||||
// optional/dynamic, is settable, or is not.
|
||||
auto fnType = openedFnType->getResult()->castTo<FunctionType>();
|
||||
auto elementTy = fnType->getResult();
|
||||
if (subscript->getAttrs().hasAttribute<OptionalAttr>())
|
||||
elementTy = OptionalType::get(elementTy->getRValueType());
|
||||
else if (isDynamicResult)
|
||||
elementTy = ImplicitlyUnwrappedOptionalType::get(elementTy->getRValueType());
|
||||
if (!isRequirementOrWitnesss(locator)) {
|
||||
if (subscript->getAttrs().hasAttribute<OptionalAttr>())
|
||||
elementTy = OptionalType::get(elementTy->getRValueType());
|
||||
else if (isDynamicResult) {
|
||||
elementTy = ImplicitlyUnwrappedOptionalType::get(
|
||||
elementTy->getRValueType());
|
||||
}
|
||||
}
|
||||
|
||||
type = FunctionType::get(fnType->getInput(), elementTy);
|
||||
} else if (isa<ProtocolDecl>(value->getDeclContext()) &&
|
||||
@@ -1372,8 +1386,9 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
|
||||
= getTypeOfReference(choice.getDecl(), isTypeReference,
|
||||
choice.isSpecialized(), locator);
|
||||
}
|
||||
|
||||
if (choice.getDecl()->getAttrs().hasAttribute<OptionalAttr>() &&
|
||||
|
||||
if (!isRequirementOrWitnesss(locator) &&
|
||||
choice.getDecl()->getAttrs().hasAttribute<OptionalAttr>() &&
|
||||
!isa<SubscriptDecl>(choice.getDecl())) {
|
||||
// For a non-subscript declaration that is an optional
|
||||
// requirement in a protocol, strip off the lvalue-ness (FIXME:
|
||||
|
||||
Reference in New Issue
Block a user