Skip to content

Commit c9cfe28

Browse files
committedJun 4, 2024
NCGenerics: improve diagnostics
Removing the old, ad-hoc diagnostics code improves the diagnostics we emit, since the existing diagnostics for missing conformances is already pretty good. rdar://127369509
1 parent 2ce5a33 commit c9cfe28

14 files changed

+91
-294
lines changed
 

‎include/swift/AST/DiagnosticsSema.def

+6-24
Original file line numberDiff line numberDiff line change
@@ -7811,33 +7811,15 @@ NOTE(noncopyable_parameter_ownership_suggestion, none,
78117811
"add '%0' %1", (StringRef, StringRef))
78127812
ERROR(ownership_specifier_nonescaping_closure,none,
78137813
"'%0' cannot be applied to nonescaping closure", (StringRef))
7814-
ERROR(noncopyable_generics, none,
7815-
"noncopyable type %0 cannot be used with generics yet",
7816-
(Type))
78177814
ERROR(noncopyable_generics_variadic, none,
78187815
"noncopyable type %0 cannot be used within a variadic type yet",
78197816
(Type))
7820-
ERROR(noncopyable_generics_specific, none,
7821-
"noncopyable type %0 cannot be used with generic type %1 yet",
7822-
(Type, Type))
7823-
ERROR(noncopyable_generics_erasure, none,
7824-
"noncopyable type %0 cannot be erased to copyable existential type %1",
7825-
(Type, Type))
7826-
ERROR(noncopyable_generics_metatype_cast, none,
7827-
"metatype %0 cannot be cast to %1 because %2 is noncopyable",
7828-
(Type, Type, Type))
7829-
ERROR(noncopyable_generics_generic_param, none,
7830-
"noncopyable type %0 cannot be substituted for copyable %1 %2 in %3",
7831-
(Type, DescriptiveDeclKind, Type, DeclName))
7832-
ERROR(noncopyable_generics_generic_param_metatype, none,
7833-
"metatype %4 of noncopyable type %0 cannot be substituted for copyable %1 %2 in %3",
7834-
(Type, DescriptiveDeclKind, Type, DeclName, Type))
7835-
NOTE(noncopyable_generics_implicit_copyable, none,
7836-
"%0 %1 has an implicit Copyable requirement",
7837-
(DescriptiveDeclKind, Type))
7838-
ERROR(noncopyable_element_of_pack_not_supported,none,
7839-
"parameter pack containing noncopyable element %0 is not supported",
7840-
(Type))
7817+
NOTE(noncopyable_generics_implicit_conformance_req, none,
7818+
"'where %noformat0: %noformat1' is implicit here",
7819+
(Type, Type))
7820+
NOTE(noncopyable_generics_implicit_composition, none,
7821+
"'%noformat0 & %noformat1' is implicit here",
7822+
(Type, Type))
78417823
ERROR(noncopyable_effectful_getter,none,
78427824
"%0 of noncopyable type cannot be 'async' or 'throws'", (DescriptiveDeclKind))
78437825
ERROR(noncopyable_enums_do_not_support_indirect,none,

‎include/swift/Sema/CSFix.h

-29
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,6 @@ enum class FixKind : uint8_t {
432432
/// vs.`@OtherActor () -> Void`
433433
AllowGlobalActorMismatch,
434434

435-
/// Produce an error about a type that must be Copyable
436-
MustBeCopyable,
437-
438435
/// Allow 'each' applied to a non-pack type.
439436
AllowInvalidPackElement,
440437

@@ -2139,32 +2136,6 @@ struct NoncopyableMatchFailure {
21392136
}
21402137
};
21412138

2142-
class MustBeCopyable final : public ConstraintFix {
2143-
Type noncopyableTy;
2144-
NoncopyableMatchFailure failure;
2145-
2146-
MustBeCopyable(ConstraintSystem &cs,
2147-
Type noncopyableTy,
2148-
NoncopyableMatchFailure failure,
2149-
ConstraintLocator *locator);
2150-
2151-
public:
2152-
std::string getName() const override { return "remove move-only from type"; }
2153-
2154-
bool diagnose(const Solution &solution, bool asNote = false) const override;
2155-
2156-
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override;
2157-
2158-
static MustBeCopyable *create(ConstraintSystem &cs,
2159-
Type noncopyableTy,
2160-
NoncopyableMatchFailure failure,
2161-
ConstraintLocator *locator);
2162-
2163-
static bool classof(const ConstraintFix *fix) {
2164-
return fix->getKind() == FixKind::MustBeCopyable;
2165-
}
2166-
};
2167-
21682139
class AllowInvalidPackElement final : public ConstraintFix {
21692140
Type packElementType;
21702141

‎lib/Sema/CSDiagnostics.cpp

+17-119
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,23 @@ void RequirementFailure::maybeEmitRequirementNote(const Decl *anchor, Type lhs,
539539
return;
540540
}
541541

542+
// If a requirement 'T: InvertibleProtocol' wasn't satisfied, then emit a note
543+
// explaining that this requirement was implicit, but is suppressible.
544+
if (req.getKind() == RequirementKind::Conformance &&
545+
req.getProtocolDecl()->getInvertibleProtocolKind() &&
546+
req.getFirstType()->is<SubstitutableType>()) {
547+
auto diag = diag::noncopyable_generics_implicit_conformance_req;
548+
549+
// Handle 'some X' where the '& InvertibleProtocol' is implicit
550+
if (auto substTy = req.getFirstType()->getAs<GenericTypeParamType>())
551+
if (auto gtpd = substTy->getDecl())
552+
if (gtpd->isOpaqueType())
553+
diag = diag::noncopyable_generics_implicit_composition;
554+
555+
emitDiagnosticAt(anchor, diag, req.getFirstType(), req.getSecondType());
556+
return;
557+
}
558+
542559
if (req.getKind() == RequirementKind::Layout ||
543560
rhs->isEqual(req.getSecondType())) {
544561
// If the note is tautological, bail out.
@@ -637,20 +654,6 @@ bool MissingConformanceFailure::diagnoseAsError() {
637654
if (diagnoseAsAmbiguousOperatorRef())
638655
return true;
639656

640-
// Use tailored diagnostics for failure to conform to Copyable.
641-
if (auto asProtoType = protocolType->getAs<ProtocolType>()) {
642-
if (auto *protoDecl = asProtoType->getDecl()) {
643-
if (protoDecl->isSpecificProtocol(KnownProtocolKind::Copyable)) {
644-
NotCopyableFailure failure(getSolution(),
645-
nonConformingType,
646-
NoncopyableMatchFailure::forCopyableConstraint(),
647-
getLocator());
648-
if (failure.diagnoseAsError())
649-
return true;
650-
}
651-
}
652-
}
653-
654657
if (nonConformingType->isObjCExistentialType()) {
655658
emitDiagnostic(diag::protocol_does_not_conform_static, nonConformingType,
656659
protocolType);
@@ -6348,111 +6351,6 @@ bool NotCompileTimeConstFailure::diagnoseAsError() {
63486351
return true;
63496352
}
63506353

6351-
bool NotCopyableFailure::diagnoseAsError() {
6352-
switch (failure.getKind()) {
6353-
case NoncopyableMatchFailure::ExistentialCast: {
6354-
if (noncopyableTy->is<AnyMetatypeType>())
6355-
emitDiagnostic(diag::noncopyable_generics_metatype_cast,
6356-
noncopyableTy,
6357-
failure.getType(),
6358-
noncopyableTy->getMetatypeInstanceType());
6359-
else
6360-
emitDiagnostic(diag::noncopyable_generics_erasure,
6361-
noncopyableTy,
6362-
failure.getType());
6363-
return true;
6364-
}
6365-
6366-
case NoncopyableMatchFailure::CopyableConstraint: {
6367-
ConstraintLocator *loc = getLocator();
6368-
auto path = loc->getPath();
6369-
6370-
if (loc->isLastElement<LocatorPathElt::AnyTupleElement>()) {
6371-
assert(!noncopyableTy->is<TupleType>() && "will use poor wording");
6372-
emitDiagnostic(diag::tuple_move_only_not_supported, noncopyableTy);
6373-
return true;
6374-
}
6375-
6376-
if (loc->isLastElement<LocatorPathElt::PackElement>()) {
6377-
emitDiagnostic(diag::noncopyable_element_of_pack_not_supported,
6378-
noncopyableTy);
6379-
return true;
6380-
}
6381-
6382-
auto diagnoseGenericTypeParamType = [&](GenericTypeParamType *typeParam) {
6383-
if (!typeParam)
6384-
return false;
6385-
6386-
if (auto *paramDecl = typeParam->getDecl()) {
6387-
if (auto *owningDecl =
6388-
dyn_cast_or_null<ValueDecl>(paramDecl->getDeclContext()->getAsDecl())) {
6389-
6390-
// FIXME: these owningDecl names are kinda bad. like just `init(describing:)`
6391-
if (noncopyableTy->is<AnyMetatypeType>())
6392-
emitDiagnostic(diag::noncopyable_generics_generic_param_metatype,
6393-
noncopyableTy->getMetatypeInstanceType(),
6394-
paramDecl->getDescriptiveKind(),
6395-
typeParam,
6396-
owningDecl->getName(),
6397-
noncopyableTy);
6398-
else
6399-
emitDiagnostic(diag::noncopyable_generics_generic_param,
6400-
noncopyableTy,
6401-
paramDecl->getDescriptiveKind(),
6402-
typeParam,
6403-
owningDecl->getName());
6404-
6405-
// If we have a location for the parameter, point it out in a note.
6406-
if (auto loc = paramDecl->getNameLoc()) {
6407-
emitDiagnosticAt(loc,
6408-
diag::noncopyable_generics_implicit_copyable,
6409-
paramDecl->getDescriptiveKind(),
6410-
typeParam);
6411-
}
6412-
6413-
return true;
6414-
}
6415-
}
6416-
return false;
6417-
};
6418-
6419-
// NOTE: a non-requirement constraint locator might now be impossible.
6420-
if (diagnoseGenericTypeParamType(loc->getGenericParameter()))
6421-
return true;
6422-
6423-
if (auto tpr =
6424-
loc->getLastElementAs<LocatorPathElt::TypeParameterRequirement>()) {
6425-
auto signature = path[path.size() - 2]
6426-
.castTo<LocatorPathElt::OpenedGeneric>()
6427-
.getSignature();
6428-
auto requirement = signature.getRequirements()[tpr->getIndex()];
6429-
auto subject = requirement.getFirstType();
6430-
6431-
if (diagnoseGenericTypeParamType(subject->getAs<GenericTypeParamType>()))
6432-
return true;
6433-
}
6434-
6435-
if (loc->getLastElementAs<LocatorPathElt::ConditionalRequirement>())
6436-
return false; // Allow MissingConformanceFailure to diagnose instead.
6437-
6438-
break;
6439-
}
6440-
} // end switch
6441-
6442-
// emit catch-all diagnostic
6443-
emitDiagnostic(diag::noncopyable_generics, noncopyableTy);
6444-
6445-
#ifndef NDEBUG
6446-
#pragma clang diagnostic push
6447-
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
6448-
getLocator()->dump(&getConstraintSystem());
6449-
#pragma clang diagnostic pop
6450-
llvm_unreachable("NoncopyableGenerics: vague diagnostic for locator");
6451-
#endif
6452-
6453-
return true;
6454-
}
6455-
64566354
bool InvalidPackElement::diagnoseAsError() {
64576355
emitDiagnostic(diag::each_non_pack, packElementType);
64586356
return true;

‎lib/Sema/CSDiagnostics.h

-14
Original file line numberDiff line numberDiff line change
@@ -1861,20 +1861,6 @@ class NotCompileTimeConstFailure final : public FailureDiagnostic {
18611861
bool diagnoseAsError() override;
18621862
};
18631863

1864-
class NotCopyableFailure final : public FailureDiagnostic {
1865-
Type noncopyableTy;
1866-
NoncopyableMatchFailure failure;
1867-
public:
1868-
NotCopyableFailure(const Solution &solution,
1869-
Type noncopyableTy,
1870-
NoncopyableMatchFailure failure,
1871-
ConstraintLocator *locator)
1872-
: FailureDiagnostic(solution, locator),
1873-
noncopyableTy(noncopyableTy), failure(failure) {}
1874-
1875-
bool diagnoseAsError() override;
1876-
};
1877-
18781864
/// Diagnose \c each applied to an expression that is not a pack type.
18791865
class InvalidPackElement final : public FailureDiagnostic {
18801866
Type packElementType;

‎lib/Sema/CSFix.cpp

-39
Original file line numberDiff line numberDiff line change
@@ -1361,45 +1361,6 @@ bool NotCompileTimeConst::diagnose(const Solution &solution, bool asNote) const
13611361
return failure.diagnose(asNote);
13621362
}
13631363

1364-
MustBeCopyable::MustBeCopyable(ConstraintSystem &cs,
1365-
Type noncopyableTy,
1366-
NoncopyableMatchFailure failure,
1367-
ConstraintLocator *locator)
1368-
: ConstraintFix(cs, FixKind::MustBeCopyable, locator, FixBehavior::Error),
1369-
noncopyableTy(noncopyableTy), failure(failure) {}
1370-
1371-
bool MustBeCopyable::diagnose(const Solution &solution, bool asNote) const {
1372-
NotCopyableFailure failDiag(solution, noncopyableTy, failure, getLocator());
1373-
return failDiag.diagnose(asNote);
1374-
}
1375-
1376-
MustBeCopyable* MustBeCopyable::create(ConstraintSystem &cs,
1377-
Type noncopyableTy,
1378-
NoncopyableMatchFailure failure,
1379-
ConstraintLocator *locator) {
1380-
return new (cs.getAllocator()) MustBeCopyable(cs, noncopyableTy,
1381-
failure, locator);
1382-
}
1383-
1384-
bool MustBeCopyable::diagnoseForAmbiguity(CommonFixesArray commonFixes) const {
1385-
// Only diagnose if all solutions agreed on the same errant non-copyable type.
1386-
Type firstNonCopyable;
1387-
for (const auto &solutionAndFix : commonFixes) {
1388-
const auto *solution = solutionAndFix.first;
1389-
const auto *fix = solutionAndFix.second->getAs<MustBeCopyable>();
1390-
1391-
auto otherNonCopyable = solution->simplifyType(fix->noncopyableTy);
1392-
if (!firstNonCopyable)
1393-
firstNonCopyable = otherNonCopyable;
1394-
1395-
if (firstNonCopyable->getCanonicalType() != otherNonCopyable->getCanonicalType()) {
1396-
return false; // fixes differed, so decline to emit a tailored diagnostic.
1397-
}
1398-
}
1399-
1400-
return diagnose(*commonFixes.front().first);
1401-
}
1402-
14031364
bool AllowInvalidPackElement::diagnose(const Solution &solution,
14041365
bool asNote) const {
14051366
InvalidPackElement failure(solution, packElementType, getLocator());

‎lib/Sema/CSSimplify.cpp

-13
Original file line numberDiff line numberDiff line change
@@ -8850,18 +8850,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
88508850
return SolutionKind::Solved;
88518851
}
88528852
}
8853-
8854-
// If this is a failure to conform to Copyable, tailor the error message.
8855-
if (kind == ConstraintKind::ConformsTo &&
8856-
protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
8857-
auto *fix =
8858-
MustBeCopyable::create(*this,
8859-
type,
8860-
NoncopyableMatchFailure::forCopyableConstraint(),
8861-
getConstraintLocator(locator));
8862-
if (!recordFix(fix))
8863-
return SolutionKind::Solved;
8864-
}
88658853
}
88668854

88678855
// There's nothing more we can do; fail.
@@ -15158,7 +15146,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1515815146
case FixKind::AllowAutoClosurePointerConversion:
1515915147
case FixKind::NotCompileTimeConst:
1516015148
case FixKind::RenameConflictingPatternVariables:
15161-
case FixKind::MustBeCopyable:
1516215149
case FixKind::AllowInvalidPackElement:
1516315150
case FixKind::AllowInvalidPackReference:
1516415151
case FixKind::AllowInvalidPackExpansion:

0 commit comments

Comments
 (0)
Please sign in to comment.