Skip to content

Commit 44ab03a

Browse files
authored
Merge pull request #66871 from kavon/generics-error-noncopyable
Be more specific than "noncopyable type T can't be used with generics yet"
2 parents 6d58bce + 8072eef commit 44ab03a

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
@@ -5520,7 +5520,9 @@ ERROR(tuple_pack_element_label,none,
55205520
"cannot use label with pack expansion tuple element",
55215521
())
55225522
ERROR(tuple_move_only_not_supported,none,
5523-
"tuples with noncopyable elements are not supported", ())
5523+
"tuple with noncopyable element type %0 is not supported", (Type))
5524+
ERROR(tuple_containing_move_only_not_supported,none,
5525+
"type %0 containing noncopyable element is not supported", (Type))
55245526
ERROR(vararg_not_allowed,none,
55255527
"variadic parameter cannot appear outside of a function parameter list",
55265528
())
@@ -7267,7 +7269,33 @@ ERROR(self_ownership_specifier_copyable,none,
72677269
(SelfAccessKind, DescriptiveDeclKind))
72687270
ERROR(ownership_specifier_nonescaping_closure,none,
72697271
"'%0' cannot be applied to nonescaping closure", (StringRef))
7270-
ERROR(noncopyable_generics, none, "noncopyable type %0 cannot be used with generics yet", (Type))
7272+
ERROR(noncopyable_generics, none,
7273+
"noncopyable type %0 cannot be used with generics yet",
7274+
(Type))
7275+
ERROR(noncopyable_generics_variadic, none,
7276+
"noncopyable type %0 cannot be used within a variadic type yet",
7277+
(Type))
7278+
ERROR(noncopyable_generics_specific, none,
7279+
"noncopyable type %0 cannot be used with generic type %1 yet",
7280+
(Type, Type))
7281+
ERROR(noncopyable_generics_erasure, none,
7282+
"noncopyable type %0 cannot be erased to copyable existential type %1",
7283+
(Type, Type))
7284+
ERROR(noncopyable_generics_metatype_cast, none,
7285+
"metatype %0 cannot be cast to %1 because %2 is noncopyable",
7286+
(Type, Type, Type))
7287+
ERROR(noncopyable_generics_generic_param, none,
7288+
"noncopyable type %0 cannot be substituted for copyable %1 %2 in %3",
7289+
(Type, DescriptiveDeclKind, Type, DeclName))
7290+
ERROR(noncopyable_generics_generic_param_metatype, none,
7291+
"metatype %4 of noncopyable type %0 cannot be substituted for copyable %1 %2 in %3",
7292+
(Type, DescriptiveDeclKind, Type, DeclName, Type))
7293+
NOTE(noncopyable_generics_implicit_copyable, none,
7294+
"%0 %1 has an implicit Copyable requirement",
7295+
(DescriptiveDeclKind, Type))
7296+
ERROR(noncopyable_element_of_pack_not_supported,none,
7297+
"parameter pack containing noncopyable element %0 is not supported",
7298+
(Type))
72717299
ERROR(noncopyable_effectful_getter,none,
72727300
"%0 of noncopyable type cannot be 'async' or 'throws'", (DescriptiveDeclKind))
72737301
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
@@ -6154,6 +6154,72 @@ bool NotCompileTimeConstFailure::diagnoseAsError() {
61546154
}
61556155

61566156
bool NotCopyableFailure::diagnoseAsError() {
6157+
switch (failure.getKind()) {
6158+
case NoncopyableMatchFailure::ExistentialCast: {
6159+
if (noncopyableTy->is<AnyMetatypeType>())
6160+
emitDiagnostic(diag::noncopyable_generics_metatype_cast,
6161+
noncopyableTy,
6162+
failure.getType(),
6163+
noncopyableTy->getMetatypeInstanceType());
6164+
else
6165+
emitDiagnostic(diag::noncopyable_generics_erasure,
6166+
noncopyableTy,
6167+
failure.getType());
6168+
return true;
6169+
}
6170+
6171+
case NoncopyableMatchFailure::CopyableConstraint: {
6172+
auto *loc = getLocator();
6173+
6174+
if (loc->isLastElement<LocatorPathElt::AnyTupleElement>()) {
6175+
assert(!noncopyableTy->is<TupleType>() && "will use poor wording");
6176+
emitDiagnostic(diag::tuple_move_only_not_supported, noncopyableTy);
6177+
return true;
6178+
}
6179+
6180+
if (loc->isLastElement<LocatorPathElt::PackElement>()) {
6181+
emitDiagnostic(diag::noncopyable_element_of_pack_not_supported,
6182+
noncopyableTy);
6183+
return true;
6184+
}
6185+
6186+
// a bit paranoid of nulls and such...
6187+
if (auto *genericParam = loc->getGenericParameter()) {
6188+
if (auto *paramDecl = genericParam->getDecl()) {
6189+
if (auto *owningDecl =
6190+
dyn_cast_or_null<ValueDecl>(paramDecl->getDeclContext()->getAsDecl())) {
6191+
6192+
// FIXME: these owningDecl names are kinda bad. like just `init(describing:)`
6193+
if (noncopyableTy->is<AnyMetatypeType>())
6194+
emitDiagnostic(diag::noncopyable_generics_generic_param_metatype,
6195+
noncopyableTy->getMetatypeInstanceType(),
6196+
paramDecl->getDescriptiveKind(),
6197+
genericParam,
6198+
owningDecl->getName(),
6199+
noncopyableTy);
6200+
else
6201+
emitDiagnostic(diag::noncopyable_generics_generic_param,
6202+
noncopyableTy,
6203+
paramDecl->getDescriptiveKind(),
6204+
genericParam,
6205+
owningDecl->getName());
6206+
6207+
// If we have a location for the parameter, point it out in a note.
6208+
if (auto loc = paramDecl->getNameLoc()) {
6209+
emitDiagnosticAt(loc,
6210+
diag::noncopyable_generics_implicit_copyable,
6211+
paramDecl->getDescriptiveKind(),
6212+
genericParam);
6213+
}
6214+
6215+
return true;
6216+
}
6217+
}
6218+
}
6219+
break;
6220+
}
6221+
}
6222+
61576223
emitDiagnostic(diag::noncopyable_generics, noncopyableTy);
61586224
return true;
61596225
}

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

@@ -1829,9 +1829,14 @@ class NotCompileTimeConstFailure final : public FailureDiagnostic {
18291829

18301830
class NotCopyableFailure final : public FailureDiagnostic {
18311831
Type noncopyableTy;
1832+
NoncopyableMatchFailure failure;
18321833
public:
1833-
NotCopyableFailure(const Solution &solution, Type noncopyableTy, ConstraintLocator *locator)
1834-
: FailureDiagnostic(solution, locator), noncopyableTy(noncopyableTy) {}
1834+
NotCopyableFailure(const Solution &solution,
1835+
Type noncopyableTy,
1836+
NoncopyableMatchFailure failure,
1837+
ConstraintLocator *locator)
1838+
: FailureDiagnostic(solution, locator),
1839+
noncopyableTy(noncopyableTy), failure(failure) {}
18351840

18361841
bool diagnoseAsError() override;
18371842
};

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
}
@@ -8492,7 +8495,10 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
84928495
// If this is a failure to conform to Copyable, tailor the error message.
84938496
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
84948497
auto *fix =
8495-
MustBeCopyable::create(*this, type, getConstraintLocator(locator));
8498+
MustBeCopyable::create(*this,
8499+
type,
8500+
NoncopyableMatchFailure::forCopyableConstraint(),
8501+
getConstraintLocator(locator));
84968502
if (!recordFix(fix))
84978503
return SolutionKind::Solved;
84988504
}

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)