Skip to content

Commit e5c99ca

Browse files
authored
Merge pull request swiftlang#27769 from hborla/anyobject-conformance-failure
[ConstraintSystem] Diagnose missing AnyObject conformance using the MissingConformance constraint fix.
2 parents 434d247 + dca1373 commit e5c99ca

File tree

13 files changed

+86
-198
lines changed

13 files changed

+86
-198
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,12 +1727,18 @@ ERROR(type_does_not_conform_owner,none,
17271727
ERROR(type_does_not_conform_in_decl_ref,none,
17281728
"referencing %0 %1 on %2 requires that %3 conform to %4",
17291729
(DescriptiveDeclKind, DeclName, Type, Type, Type))
1730+
ERROR(type_does_not_conform_anyobject_in_decl_ref,none,
1731+
"referencing %0 %1 on %2 requires that %3 be a class type",
1732+
(DescriptiveDeclKind, DeclName, Type, Type, Type))
17301733
ERROR(type_does_not_conform_decl_owner,none,
17311734
"%0 %1 requires that %2 conform to %3",
17321735
(DescriptiveDeclKind, DeclName, Type, Type))
1733-
ERROR(type_does_not_conform_in_opaque_return,none,
1734-
"return type of %0 %1 requires that %2 conform to %3",
1736+
ERROR(type_does_not_conform_anyobject_decl_owner,none,
1737+
"%0 %1 requires that %2 be a class type",
17351738
(DescriptiveDeclKind, DeclName, Type, Type))
1739+
ERROR(type_does_not_conform_in_opaque_return,none,
1740+
"return type of %0 %1 requires that %2 %select{conform to %3|be a class type}4",
1741+
(DescriptiveDeclKind, DeclName, Type, Type, bool))
17361742
ERROR(types_not_equal_decl,none,
17371743
"%0 %1 requires the types %2 and %3 be equivalent",
17381744
(DescriptiveDeclKind, DeclName, Type, Type))
@@ -1751,6 +1757,8 @@ NOTE(where_requirement_failure_both_subst,none,
17511757
"where %0 = %1, %2 = %3", (Type, Type, Type, Type))
17521758
NOTE(requirement_implied_by_conditional_conformance,none,
17531759
"requirement from conditional conformance of %0 to %1", (Type, Type))
1760+
NOTE(wrapped_type_satisfies_requirement,none,
1761+
"wrapped type %0 satisfies this requirement; did you mean to unwrap?", (Type))
17541762
NOTE(candidate_types_conformance_requirement,none,
17551763
"candidate requires that %0 conform to %1 "
17561764
"(requirement specified as %2 == %3%4)",

lib/Sema/CSDiag.cpp

Lines changed: 0 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -651,142 +651,6 @@ bool FailureDiagnosis::diagnoseGeneralOverloadFailure(Constraint *constraint) {
651651
return true;
652652
}
653653

654-
static bool
655-
diagnoseUnresolvedDotExprTypeRequirementFailure(ConstraintSystem &cs,
656-
Constraint *constraint) {
657-
auto &TC = cs.TC;
658-
659-
auto *locator = constraint->getLocator();
660-
if (!locator)
661-
return false;
662-
663-
664-
auto reqElt =
665-
locator->getLastElementAs<LocatorPathElt::TypeParameterRequirement>();
666-
if (!reqElt)
667-
return false;
668-
669-
auto *anchor = locator->getAnchor();
670-
if (!anchor)
671-
return false;
672-
673-
auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor);
674-
if (!UDE)
675-
return false;
676-
677-
auto ownerType = cs.getType(UDE->getBase());
678-
if (!ownerType)
679-
return false;
680-
681-
ownerType = cs.simplifyType(ownerType)->getWithoutSpecifierType();
682-
if (ownerType->hasTypeVariable() || ownerType->hasUnresolvedType())
683-
return false;
684-
685-
// If we actually resolved the member to use, use it.
686-
auto loc = cs.getConstraintLocator(UDE, ConstraintLocator::Member);
687-
auto *member = cs.findResolvedMemberRef(loc);
688-
// If the problem is contextual it's diagnosed elsewhere.
689-
if (!member || !member->getAsGenericContext())
690-
return false;
691-
692-
auto req = member->getAsGenericContext()
693-
->getGenericSignature()
694-
->getRequirements()[reqElt->getIndex()];
695-
696-
Diag<Type, Type, Type, Type, StringRef> note;
697-
switch (req.getKind()) {
698-
case RequirementKind::Conformance:
699-
case RequirementKind::Layout:
700-
return false;
701-
702-
case RequirementKind::Superclass:
703-
note = diag::candidate_types_inheritance_requirement;
704-
break;
705-
706-
case RequirementKind::SameType:
707-
note = diag::candidate_types_equal_requirement;
708-
break;
709-
}
710-
711-
TC.diagnose(UDE->getLoc(), diag::could_not_find_value_member, ownerType,
712-
UDE->getName());
713-
714-
auto first = cs.simplifyType(constraint->getFirstType());
715-
auto second = cs.simplifyType(constraint->getSecondType());
716-
auto rawFirstType = req.getFirstType();
717-
auto rawSecondType = req.getSecondType();
718-
719-
TC.diagnose(member, note, first, second, rawFirstType, rawSecondType, "");
720-
721-
return true;
722-
}
723-
724-
/// Diagnose problems related to failures in constraints
725-
/// generated by `openGeneric` which represent different
726-
/// kinds of type parameter requirements.
727-
static bool diagnoseTypeRequirementFailure(ConstraintSystem &cs,
728-
Constraint *constraint) {
729-
auto &TC = cs.TC;
730-
731-
auto *locator = constraint->getLocator();
732-
if (!locator)
733-
return false;
734-
735-
auto path = locator->getPath();
736-
if (path.empty())
737-
return false;
738-
739-
auto &last = path.back();
740-
if (last.getKind() != ConstraintLocator::TypeParameterRequirement)
741-
return false;
742-
743-
auto *anchor = locator->getAnchor();
744-
if (!anchor)
745-
return false;
746-
747-
auto ownerType = cs.getType(anchor);
748-
749-
if (isa<UnresolvedMemberExpr>(anchor))
750-
ownerType = cs.getContextualType();
751-
else if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor))
752-
ownerType = cs.getType(UDE->getBase());
753-
754-
if (!ownerType)
755-
return false;
756-
757-
ownerType = cs.simplifyType(ownerType)->getWithoutSpecifierType();
758-
if (ownerType->hasTypeVariable() || ownerType->hasUnresolvedType())
759-
return false;
760-
761-
if (diagnoseUnresolvedDotExprTypeRequirementFailure(cs, constraint))
762-
return true;
763-
764-
auto lhs = cs.simplifyType(constraint->getFirstType());
765-
auto rhs = cs.simplifyType(constraint->getSecondType());
766-
767-
switch (constraint->getKind()) {
768-
case ConstraintKind::ConformsTo:
769-
TC.diagnose(anchor->getLoc(), diag::type_does_not_conform_owner, ownerType,
770-
lhs, rhs);
771-
return true;
772-
773-
case ConstraintKind::Subtype: // superclass
774-
TC.diagnose(anchor->getLoc(), diag::type_does_not_inherit, ownerType, lhs,
775-
rhs);
776-
return true;
777-
778-
case ConstraintKind::Bind: { // same type
779-
TC.diagnose(anchor->getLoc(), diag::types_not_equal, ownerType, lhs, rhs);
780-
return true;
781-
}
782-
783-
default:
784-
break;
785-
}
786-
787-
return false;
788-
}
789-
790654
bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
791655
auto anchor = expr;
792656
bool resolvedAnchorToExpr = false;
@@ -964,9 +828,6 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
964828
}
965829
}
966830

967-
if (diagnoseTypeRequirementFailure(CS, constraint))
968-
return true;
969-
970831
diagnose(anchor->getLoc(), diag::types_not_convertible,
971832
constraint->getKind() == ConstraintKind::Subtype,
972833
fromType, toType)

lib/Sema/CSDiagnostics.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,8 @@ bool RequirementFailure::diagnoseAsError() {
478478
auto *namingDecl = OTD->getNamingDecl();
479479
emitDiagnostic(
480480
anchor->getLoc(), diag::type_does_not_conform_in_opaque_return,
481-
namingDecl->getDescriptiveKind(), namingDecl->getFullName(), lhs, rhs);
481+
namingDecl->getDescriptiveKind(), namingDecl->getFullName(), lhs, rhs,
482+
rhs->isAnyObject());
482483

483484
if (auto *repr = namingDecl->getOpaqueResultTypeRepr()) {
484485
emitDiagnostic(repr->getLoc(), diag::opaque_return_type_declared_here)
@@ -517,14 +518,27 @@ void RequirementFailure::emitRequirementNote(const Decl *anchor, Type lhs,
517518
Type rhs) const {
518519
auto &req = getRequirement();
519520

521+
if (req.getKind() != RequirementKind::SameType) {
522+
if (auto wrappedType = lhs->getOptionalObjectType()) {
523+
auto &tc = getTypeChecker();
524+
auto kind = (req.getKind() == RequirementKind::Superclass ?
525+
ConstraintKind::Subtype : ConstraintKind::ConformsTo);
526+
if (tc.typesSatisfyConstraint(wrappedType, rhs, /*openArchetypes=*/false,
527+
kind, getDC()))
528+
emitDiagnostic(getAnchor()->getLoc(),
529+
diag::wrapped_type_satisfies_requirement, wrappedType);
530+
}
531+
}
532+
520533
if (isConditional()) {
521534
emitDiagnostic(anchor, diag::requirement_implied_by_conditional_conformance,
522535
resolveType(Conformance->getType()),
523536
Conformance->getProtocol()->getDeclaredInterfaceType());
524537
return;
525538
}
526539

527-
if (rhs->isEqual(req.getSecondType())) {
540+
if (req.getKind() == RequirementKind::Layout ||
541+
rhs->isEqual(req.getSecondType())) {
528542
emitDiagnostic(anchor, diag::where_requirement_failure_one_subst,
529543
req.getFirstType(), lhs);
530544
return;
@@ -589,7 +603,8 @@ bool MissingConformanceFailure::diagnoseAsError() {
589603

590604
bool MissingConformanceFailure::diagnoseTypeCannotConform(Expr *anchor,
591605
Type nonConformingType, Type protocolType) const {
592-
if (!(nonConformingType->is<AnyFunctionType>() ||
606+
if (getRequirement().getKind() == RequirementKind::Layout ||
607+
!(nonConformingType->is<AnyFunctionType>() ||
593608
nonConformingType->is<TupleType>() ||
594609
nonConformingType->isExistentialType() ||
595610
nonConformingType->is<AnyMetatypeType>())) {

lib/Sema/CSDiagnostics.h

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,8 @@ class RequirementFailure : public FailureDiagnostic {
320320
Type LHS, RHS;
321321

322322
public:
323-
RequirementFailure(ConstraintSystem &cs, Expr *expr, RequirementKind kind,
324-
Type lhs, Type rhs, ConstraintLocator *locator)
323+
RequirementFailure(ConstraintSystem &cs, Expr *expr, Type lhs, Type rhs,
324+
ConstraintLocator *locator)
325325
: FailureDiagnostic(expr, cs, locator),
326326
Conformance(getConformanceForConditionalReq(locator)),
327327
Signature(getSignature(locator)), AffectedDecl(getDeclRef()),
@@ -334,9 +334,6 @@ class RequirementFailure : public FailureDiagnostic {
334334
assert(getGenericContext() &&
335335
"Affected decl not within a generic context?");
336336

337-
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
338-
assert(reqElt.getRequirementKind() == kind);
339-
340337
// It's possible sometimes not to have no base expression.
341338
if (!expr)
342339
return;
@@ -418,8 +415,12 @@ class MissingConformanceFailure final : public RequirementFailure {
418415
MissingConformanceFailure(Expr *expr, ConstraintSystem &cs,
419416
ConstraintLocator *locator,
420417
std::pair<Type, Type> conformance)
421-
: RequirementFailure(cs, expr, RequirementKind::Conformance,
422-
conformance.first, conformance.second, locator) {}
418+
: RequirementFailure(cs, expr, conformance.first, conformance.second,
419+
locator) {
420+
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
421+
assert(reqElt.getRequirementKind() == RequirementKind::Conformance ||
422+
reqElt.getRequirementKind() == RequirementKind::Layout);
423+
}
423424

424425
bool diagnoseAsError() override;
425426

@@ -433,11 +434,15 @@ class MissingConformanceFailure final : public RequirementFailure {
433434
bool diagnoseAsAmbiguousOperatorRef();
434435

435436
DiagOnDecl getDiagnosticOnDecl() const override {
436-
return diag::type_does_not_conform_decl_owner;
437+
return (getRequirement().getKind() == RequirementKind::Layout ?
438+
diag::type_does_not_conform_anyobject_decl_owner :
439+
diag::type_does_not_conform_decl_owner);
437440
}
438441

439442
DiagInReference getDiagnosticInRereference() const override {
440-
return diag::type_does_not_conform_in_decl_ref;
443+
return (getRequirement().getKind() == RequirementKind::Layout ?
444+
diag::type_does_not_conform_anyobject_in_decl_ref :
445+
diag::type_does_not_conform_in_decl_ref);
441446
}
442447

443448
DiagAsNote getDiagnosticAsNote() const override {
@@ -468,8 +473,10 @@ class SameTypeRequirementFailure final : public RequirementFailure {
468473
public:
469474
SameTypeRequirementFailure(Expr *expr, ConstraintSystem &cs, Type lhs,
470475
Type rhs, ConstraintLocator *locator)
471-
: RequirementFailure(cs, expr, RequirementKind::SameType, lhs, rhs,
472-
locator) {}
476+
: RequirementFailure(cs, expr, lhs, rhs, locator) {
477+
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
478+
assert(reqElt.getRequirementKind() == RequirementKind::SameType);
479+
}
473480

474481
protected:
475482
DiagOnDecl getDiagnosticOnDecl() const override {
@@ -502,8 +509,10 @@ class SuperclassRequirementFailure final : public RequirementFailure {
502509
public:
503510
SuperclassRequirementFailure(Expr *expr, ConstraintSystem &cs, Type lhs,
504511
Type rhs, ConstraintLocator *locator)
505-
: RequirementFailure(cs, expr, RequirementKind::Superclass, lhs, rhs,
506-
locator) {}
512+
: RequirementFailure(cs, expr, lhs, rhs, locator) {
513+
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
514+
assert(reqElt.getRequirementKind() == RequirementKind::Superclass);
515+
}
507516

508517
protected:
509518
DiagOnDecl getDiagnosticOnDecl() const override {

lib/Sema/CSSimplify.cpp

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,6 +2015,12 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
20152015
if (req &&
20162016
req->getRequirementKind() == RequirementKind::Superclass)
20172017
return getTypeMatchSuccess();
2018+
2019+
auto *fix = fixRequirementFailure(*this, type1, type2, locator);
2020+
if (fix && !recordFix(fix)) {
2021+
recordFixedRequirement(type1, RequirementKind::Layout, type2);
2022+
return getTypeMatchSuccess();
2023+
}
20182024
}
20192025
}
20202026

@@ -3437,8 +3443,10 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
34373443
if (shouldAttemptFixes()) {
34383444
auto last = locator.last();
34393445
// If this happens as part of the argument-to-parameter
3440-
// conversion, there is a tailored fix/diagnostic.
3441-
if (last && last->is<LocatorPathElt::ApplyArgToParam>())
3446+
// conversion or type requirement, there is a tailored
3447+
// fix/diagnostic.
3448+
if (last && (last->is<LocatorPathElt::ApplyArgToParam>() ||
3449+
last->is<LocatorPathElt::AnyRequirement>()))
34423450
break;
34433451
}
34443452
// If two module types or archetypes were not already equal, there's
@@ -4339,24 +4347,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
43394347
if (!shouldAttemptFixes())
43404348
return SolutionKind::Error;
43414349

4342-
// See if there's anything we can do to fix the conformance:
4343-
if (auto optionalObjectType = type->getOptionalObjectType()) {
4344-
TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);
4345-
// The underlying type of an optional may conform to the protocol if the
4346-
// optional doesn't; suggest forcing if that's the case.
4347-
auto result = simplifyConformsToConstraint(
4348-
optionalObjectType, protocol, kind,
4349-
locator.withPathElement(LocatorPathElt::GenericArgument(0)), subflags);
4350-
if (result == SolutionKind::Solved) {
4351-
auto *fix = ForceOptional::create(*this, type, optionalObjectType,
4352-
getConstraintLocator(locator));
4353-
if (recordFix(fix)) {
4354-
return SolutionKind::Error;
4355-
}
4356-
}
4357-
return result;
4358-
}
4359-
43604350
auto protocolTy = protocol->getDeclaredType();
43614351
// If this conformance has been fixed already, let's just consider this done.
43624352
if (hasFixedRequirement(type, RequirementKind::Conformance, protocolTy))

test/APINotes/versioned-objc.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class ProtoWithVersionedUnavailableMemberImpl: ProtoWithVersionedUnavailableMemb
1616
func testNonGeneric() {
1717
// CHECK-DIAGS-4:[[@LINE+1]]:{{[0-9]+}}: error: cannot convert value of type 'Any' to specified type 'Int'
1818
let _: Int = NewlyGenericSub.defaultElement()
19-
// CHECK-DIAGS-5:[[@LINE-1]]:{{[0-9]+}}: error: generic parameter 'Element' could not be inferred
19+
// CHECK-DIAGS-5:[[@LINE-1]]:{{[0-9]+}}: error: generic class 'NewlyGenericSub' requires that 'Int' be a class type
2020

2121
// CHECK-DIAGS-4:[[@LINE+1]]:{{[0-9]+}}: error: cannot specialize non-generic type 'NewlyGenericSub'
2222
let _: Int = NewlyGenericSub<Base>.defaultElement()

0 commit comments

Comments
 (0)