Skip to content

Commit 2a62070

Browse files
authored
Merge pull request #66946 from kavon/5.9-generics-error-noncopyable
[5.9🍒] Be more specific than "noncopyable type T can't be used with generics yet"
2 parents 099d9cb + c3d2618 commit 2a62070

14 files changed

+344
-150
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5448,7 +5448,9 @@ ERROR(tuple_pack_element_label,none,
54485448
"cannot use label with pack expansion tuple element",
54495449
())
54505450
ERROR(tuple_move_only_not_supported,none,
5451-
"tuples with noncopyable elements are not supported", ())
5451+
"tuple with noncopyable element type %0 is not supported", (Type))
5452+
ERROR(tuple_containing_move_only_not_supported,none,
5453+
"type %0 containing noncopyable element is not supported", (Type))
54525454
ERROR(vararg_not_allowed,none,
54535455
"variadic parameter cannot appear outside of a function parameter list",
54545456
())
@@ -7195,7 +7197,33 @@ ERROR(self_ownership_specifier_copyable,none,
71957197
(SelfAccessKind, DescriptiveDeclKind))
71967198
ERROR(ownership_specifier_nonescaping_closure,none,
71977199
"'%0' cannot be applied to nonescaping closure", (StringRef))
7198-
ERROR(noncopyable_generics, none, "noncopyable type %0 cannot be used with generics yet", (Type))
7200+
ERROR(noncopyable_generics, none,
7201+
"noncopyable type %0 cannot be used with generics yet",
7202+
(Type))
7203+
ERROR(noncopyable_generics_variadic, none,
7204+
"noncopyable type %0 cannot be used within a variadic type yet",
7205+
(Type))
7206+
ERROR(noncopyable_generics_specific, none,
7207+
"noncopyable type %0 cannot be used with generic type %1 yet",
7208+
(Type, Type))
7209+
ERROR(noncopyable_generics_erasure, none,
7210+
"noncopyable type %0 cannot be erased to copyable existential type %1",
7211+
(Type, Type))
7212+
ERROR(noncopyable_generics_metatype_cast, none,
7213+
"metatype %0 cannot be cast to %1 because %2 is noncopyable",
7214+
(Type, Type, Type))
7215+
ERROR(noncopyable_generics_generic_param, none,
7216+
"noncopyable type %0 cannot be substituted for copyable %1 %2 in %3",
7217+
(Type, DescriptiveDeclKind, Type, DeclName))
7218+
ERROR(noncopyable_generics_generic_param_metatype, none,
7219+
"metatype %4 of noncopyable type %0 cannot be substituted for copyable %1 %2 in %3",
7220+
(Type, DescriptiveDeclKind, Type, DeclName, Type))
7221+
NOTE(noncopyable_generics_implicit_copyable, none,
7222+
"%0 %1 has an implicit Copyable requirement",
7223+
(DescriptiveDeclKind, Type))
7224+
ERROR(noncopyable_element_of_pack_not_supported,none,
7225+
"parameter pack containing noncopyable element %0 is not supported",
7226+
(Type))
71997227
ERROR(noncopyable_effectful_getter,none,
72007228
"%0 of noncopyable type cannot be 'async' or 'throws'", (DescriptiveDeclKind))
72017229
ERROR(noncopyable_enums_do_not_support_indirect,none,

include/swift/Sema/CSFix.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2082,10 +2082,53 @@ class NotCompileTimeConst final : public ContextualMismatch {
20822082
}
20832083
};
20842084

2085+
/// Describes the reason why the type must be copyable
2086+
struct NoncopyableMatchFailure {
2087+
enum Kind {
2088+
CopyableConstraint,
2089+
ExistentialCast,
2090+
};
2091+
2092+
private:
2093+
Kind reason;
2094+
union {
2095+
Type type;
2096+
};
2097+
2098+
NoncopyableMatchFailure(Kind reason, Type type)
2099+
: reason(reason), type(type) {}
2100+
2101+
public:
2102+
Kind getKind() const { return reason; }
2103+
2104+
Type getType() const {
2105+
switch (reason) {
2106+
case ExistentialCast:
2107+
return type;
2108+
2109+
case CopyableConstraint:
2110+
llvm_unreachable("no type payload");
2111+
};
2112+
}
2113+
2114+
static NoncopyableMatchFailure forCopyableConstraint() {
2115+
return NoncopyableMatchFailure(CopyableConstraint, Type());
2116+
}
2117+
2118+
static NoncopyableMatchFailure forExistentialCast(Type existential) {
2119+
assert(existential->isAnyExistentialType());
2120+
return NoncopyableMatchFailure(ExistentialCast, existential);
2121+
}
2122+
};
2123+
20852124
class MustBeCopyable final : public ConstraintFix {
20862125
Type noncopyableTy;
2126+
NoncopyableMatchFailure failure;
20872127

2088-
MustBeCopyable(ConstraintSystem &cs, Type noncopyableTy, ConstraintLocator *locator);
2128+
MustBeCopyable(ConstraintSystem &cs,
2129+
Type noncopyableTy,
2130+
NoncopyableMatchFailure failure,
2131+
ConstraintLocator *locator);
20892132

20902133
public:
20912134
std::string getName() const override { return "remove move-only from type"; }
@@ -2096,6 +2139,7 @@ class MustBeCopyable final : public ConstraintFix {
20962139

20972140
static MustBeCopyable *create(ConstraintSystem &cs,
20982141
Type noncopyableTy,
2142+
NoncopyableMatchFailure failure,
20992143
ConstraintLocator *locator);
21002144

21012145
static bool classof(const ConstraintFix *fix) {

lib/Sema/CSDiagnostics.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6095,6 +6095,72 @@ bool NotCompileTimeConstFailure::diagnoseAsError() {
60956095
}
60966096

60976097
bool NotCopyableFailure::diagnoseAsError() {
6098+
switch (failure.getKind()) {
6099+
case NoncopyableMatchFailure::ExistentialCast: {
6100+
if (noncopyableTy->is<AnyMetatypeType>())
6101+
emitDiagnostic(diag::noncopyable_generics_metatype_cast,
6102+
noncopyableTy,
6103+
failure.getType(),
6104+
noncopyableTy->getMetatypeInstanceType());
6105+
else
6106+
emitDiagnostic(diag::noncopyable_generics_erasure,
6107+
noncopyableTy,
6108+
failure.getType());
6109+
return true;
6110+
}
6111+
6112+
case NoncopyableMatchFailure::CopyableConstraint: {
6113+
auto *loc = getLocator();
6114+
6115+
if (loc->isLastElement<LocatorPathElt::AnyTupleElement>()) {
6116+
assert(!noncopyableTy->is<TupleType>() && "will use poor wording");
6117+
emitDiagnostic(diag::tuple_move_only_not_supported, noncopyableTy);
6118+
return true;
6119+
}
6120+
6121+
if (loc->isLastElement<LocatorPathElt::PackElement>()) {
6122+
emitDiagnostic(diag::noncopyable_element_of_pack_not_supported,
6123+
noncopyableTy);
6124+
return true;
6125+
}
6126+
6127+
// a bit paranoid of nulls and such...
6128+
if (auto *genericParam = loc->getGenericParameter()) {
6129+
if (auto *paramDecl = genericParam->getDecl()) {
6130+
if (auto *owningDecl =
6131+
dyn_cast_or_null<ValueDecl>(paramDecl->getDeclContext()->getAsDecl())) {
6132+
6133+
// FIXME: these owningDecl names are kinda bad. like just `init(describing:)`
6134+
if (noncopyableTy->is<AnyMetatypeType>())
6135+
emitDiagnostic(diag::noncopyable_generics_generic_param_metatype,
6136+
noncopyableTy->getMetatypeInstanceType(),
6137+
paramDecl->getDescriptiveKind(),
6138+
genericParam,
6139+
owningDecl->getName(),
6140+
noncopyableTy);
6141+
else
6142+
emitDiagnostic(diag::noncopyable_generics_generic_param,
6143+
noncopyableTy,
6144+
paramDecl->getDescriptiveKind(),
6145+
genericParam,
6146+
owningDecl->getName());
6147+
6148+
// If we have a location for the parameter, point it out in a note.
6149+
if (auto loc = paramDecl->getNameLoc()) {
6150+
emitDiagnosticAt(loc,
6151+
diag::noncopyable_generics_implicit_copyable,
6152+
paramDecl->getDescriptiveKind(),
6153+
genericParam);
6154+
}
6155+
6156+
return true;
6157+
}
6158+
}
6159+
}
6160+
break;
6161+
}
6162+
}
6163+
60986164
emitDiagnostic(diag::noncopyable_generics, noncopyableTy);
60996165
return true;
61006166
}

lib/Sema/CSDiagnostics.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -539,16 +539,16 @@ class MemberAccessOnOptionalBaseFailure final : public MemberReferenceFailure {
539539
ResultTypeIsOptional(resultOptional) {}
540540

541541
bool diagnoseAsError() override;
542-
542+
543543
Type getMemberBaseType() const {
544544
return MemberBaseType;
545545
}
546-
546+
547547
SourceLoc getLoc() const override {
548548
// The end location points to the dot in the member access.
549549
return getSourceRange().End;
550550
}
551-
551+
552552
SourceRange getSourceRange() const override;
553553

554554
};
@@ -670,7 +670,7 @@ class ContextualFailure : public FailureDiagnostic {
670670

671671
/// If we're trying to convert something to `nil`.
672672
bool diagnoseConversionToNil() const;
673-
673+
674674
/// Diagnose failed conversion in a `CoerceExpr`.
675675
bool diagnoseCoercionToUnrelatedType() const;
676676

@@ -1816,9 +1816,14 @@ class NotCompileTimeConstFailure final : public FailureDiagnostic {
18161816

18171817
class NotCopyableFailure final : public FailureDiagnostic {
18181818
Type noncopyableTy;
1819+
NoncopyableMatchFailure failure;
18191820
public:
1820-
NotCopyableFailure(const Solution &solution, Type noncopyableTy, ConstraintLocator *locator)
1821-
: FailureDiagnostic(solution, locator), noncopyableTy(noncopyableTy) {}
1821+
NotCopyableFailure(const Solution &solution,
1822+
Type noncopyableTy,
1823+
NoncopyableMatchFailure failure,
1824+
ConstraintLocator *locator)
1825+
: FailureDiagnostic(solution, locator),
1826+
noncopyableTy(noncopyableTy), failure(failure) {}
18221827

18231828
bool diagnoseAsError() override;
18241829
};

lib/Sema/CSFix.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,19 +1368,24 @@ bool NotCompileTimeConst::diagnose(const Solution &solution, bool asNote) const
13681368
return failure.diagnose(asNote);
13691369
}
13701370

1371-
MustBeCopyable::MustBeCopyable(ConstraintSystem &cs, Type noncopyableTy, ConstraintLocator *locator)
1371+
MustBeCopyable::MustBeCopyable(ConstraintSystem &cs,
1372+
Type noncopyableTy,
1373+
NoncopyableMatchFailure failure,
1374+
ConstraintLocator *locator)
13721375
: ConstraintFix(cs, FixKind::MustBeCopyable, locator, FixBehavior::Error),
1373-
noncopyableTy(noncopyableTy) {}
1376+
noncopyableTy(noncopyableTy), failure(failure) {}
13741377

13751378
bool MustBeCopyable::diagnose(const Solution &solution, bool asNote) const {
1376-
NotCopyableFailure failure(solution, noncopyableTy, getLocator());
1377-
return failure.diagnose(asNote);
1379+
NotCopyableFailure failDiag(solution, noncopyableTy, failure, getLocator());
1380+
return failDiag.diagnose(asNote);
13781381
}
13791382

13801383
MustBeCopyable* MustBeCopyable::create(ConstraintSystem &cs,
13811384
Type noncopyableTy,
1385+
NoncopyableMatchFailure failure,
13821386
ConstraintLocator *locator) {
1383-
return new (cs.getAllocator()) MustBeCopyable(cs, noncopyableTy, locator);
1387+
return new (cs.getAllocator()) MustBeCopyable(cs, noncopyableTy,
1388+
failure, locator);
13841389
}
13851390

13861391
bool MustBeCopyable::diagnoseForAmbiguity(CommonFixesArray commonFixes) const {

lib/Sema/CSSimplify.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3832,8 +3832,11 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
38323832
if (type1->getMetatypeInstanceType()->isPureMoveOnly()) {
38333833
// tailor error message
38343834
if (shouldAttemptFixes()) {
3835-
auto *fix = MustBeCopyable::create(*this, type1,
3836-
getConstraintLocator(locator));
3835+
auto *fix = MustBeCopyable::create(*this,
3836+
type1,
3837+
NoncopyableMatchFailure::forExistentialCast(
3838+
type2),
3839+
getConstraintLocator(locator));
38373840
if (!recordFix(fix))
38383841
return getTypeMatchSuccess();
38393842
}
@@ -8495,7 +8498,10 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
84958498
// If this is a failure to conform to Copyable, tailor the error message.
84968499
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
84978500
auto *fix =
8498-
MustBeCopyable::create(*this, type, getConstraintLocator(locator));
8501+
MustBeCopyable::create(*this,
8502+
type,
8503+
NoncopyableMatchFailure::forCopyableConstraint(),
8504+
getConstraintLocator(locator));
84998505
if (!recordFix(fix))
85008506
return SolutionKind::Solved;
85018507
}

lib/Sema/MiscDiagnostics.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,11 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
329329
// Diagnose attempts to form a tuple with any noncopyable elements.
330330
if (E->getType()->isPureMoveOnly()
331331
&& !Ctx.LangOpts.hasFeature(Feature::MoveOnlyTuples)) {
332-
Ctx.Diags.diagnose(E->getLoc(), diag::tuple_move_only_not_supported);
332+
auto noncopyableTy = E->getType();
333+
assert(noncopyableTy->is<TupleType>() && "will use poor wording");
334+
Ctx.Diags.diagnose(E->getLoc(),
335+
diag::tuple_containing_move_only_not_supported,
336+
noncopyableTy);
333337
}
334338
}
335339

0 commit comments

Comments
 (0)