Skip to content

Commit 8a2058a

Browse files
committed
[NoncopyableGenerics] fix isNoncopyable for packs
We're not yet going to allow noncopyable types into packs, so this change prevents the use of `~Copyable` on an `each T` generic parameter. It also fixes how we query for whether a `repeat X` parameter is copyable.
1 parent 279d27a commit 8a2058a

File tree

6 files changed

+69
-5
lines changed

6 files changed

+69
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3084,6 +3084,10 @@ ERROR(requires_not_suitable_archetype,none,
30843084
"generic parameter or associated type",
30853085
(Type))
30863086

3087+
ERROR(requires_not_suitable_inverse_subject,none,
3088+
"cannot apply inverse %1 to type %0 in conformance requirement",
3089+
(Type, Type))
3090+
30873091
ERROR(invalid_shape_requirement,none,
30883092
"invalid same-shape requirement between %0 and %1",
30893093
(Type, Type))

lib/AST/RequirementMachine/Diagnostics.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,22 @@ bool swift::rewriting::diagnoseRequirementErrors(
105105
break;
106106
}
107107

108+
case RequirementError::Kind::InvalidInverseSubject: {
109+
if (error.requirement.hasError())
110+
break;
111+
112+
auto subjectType = error.requirement.getFirstType();
113+
auto constraintType = error.requirement.getSecondType();
114+
115+
assert(constraintType->is<InverseType>());
116+
assert(error.requirement.getKind() == RequirementKind::Conformance);
117+
118+
ctx.Diags.diagnose(loc, diag::requires_not_suitable_inverse_subject,
119+
subjectType, constraintType);
120+
diagnosedError = true;
121+
break;
122+
}
123+
108124
case RequirementError::Kind::InvalidShapeRequirement: {
109125
if (error.requirement.hasError())
110126
break;

lib/AST/RequirementMachine/Diagnostics.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ struct RequirementError {
3434
/// A type requirement on a trivially invalid subject type,
3535
/// e.g. Bool: Collection.
3636
InvalidRequirementSubject,
37+
/// An inverse constraint applied to an invalid subject type,
38+
/// e.g., each T : ~Copyable
39+
InvalidInverseSubject,
3740
/// An invalid shape requirement, e.g. T.shape == Int.shape
3841
InvalidShapeRequirement,
3942
/// A pair of conflicting requirements, T == Int, T == String
@@ -78,6 +81,11 @@ struct RequirementError {
7881
return {Kind::InvalidRequirementSubject, req, loc};
7982
}
8083

84+
static RequirementError forInvalidInverseSubject(Requirement req,
85+
SourceLoc loc) {
86+
return {Kind::InvalidInverseSubject, req, loc};
87+
}
88+
8189
static RequirementError forInvalidShapeRequirement(Requirement req,
8290
SourceLoc loc) {
8391
return {Kind::InvalidShapeRequirement, req, loc};

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -393,13 +393,20 @@ static void desugarConformanceRequirement(Requirement req,
393393
}
394394

395395
} else if (constraintType->is<InverseType>()) {
396+
auto subject = req.getFirstType();
397+
396398
// Fast-path
397-
if (req.getFirstType()->isTypeParameter()) {
398-
result.push_back(req);
399-
return;
399+
if (subject->isTypeParameter()) {
400+
if (!subject->isParameterPack()) {
401+
result.push_back(req);
402+
return;
403+
}
404+
// Disallow parameter packs for now.
405+
errors.push_back(RequirementError::forInvalidInverseSubject(req, loc));
406+
} else {
407+
// Only permit type-parameter subjects.
408+
errors.push_back(RequirementError::forInvalidRequirementSubject(req, loc));
400409
}
401-
// Only permit type-parameter subjects for inverse-conformance requirements.
402-
errors.push_back(RequirementError::forInvalidRequirementSubject(req, loc));
403410
}
404411

405412
for (auto subReq : subReqs)

lib/Sema/TypeCheckInvertible.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ bool IsNoncopyableRequest::evaluate(Evaluator &evaluator,
134134
assert(!type->hasTypeParameter() && "forgot to mapTypeIntoContext first");
135135
auto &ctx = type->getASTContext();
136136

137+
// Pack expansions such as `repeat T` themselves do not have conformances,
138+
// so check its pattern type for conformance.
139+
if (auto *pet = type->getAs<PackExpansionType>()) {
140+
type = pet->getPatternType()->getCanonicalType();
141+
}
142+
137143
auto *copyable = ctx.getProtocol(KnownProtocolKind::Copyable);
138144
if (!copyable)
139145
llvm_unreachable("missing Copyable protocol!");

test/Generics/inverse_copyable_requirement.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,30 @@ func tryToDoBadMetatypeStuff() {
290290
doBadMetatypeStuff(MO.self)
291291
}
292292

293+
func totallyInvalid<T>(_ t: T) where MO: ~Copyable {}
294+
// expected-error@-1{{type 'MO' in conformance requirement does not refer to a generic parameter or associated type}}
295+
293296
func packingHeat<each T>(_ t: repeat each T) {} // expected-note {{generic parameter 'each T' has an implicit Copyable requirement}}
294297
func packIt() {
295298
packingHeat(MO()) // expected-error {{noncopyable type 'MO' cannot be substituted for copyable generic parameter 'each T' in 'packingHeat'}}
299+
packingHeat(10)
300+
}
301+
302+
func packingUniqueHeat_1<each T: ~Copyable>(_ t: repeat each T) {}
303+
// expected-error@-1{{cannot apply inverse '~Copyable' to type 'each T' in conformance requirement}}
304+
// expected-note@-2{{generic parameter 'each T' has an implicit Copyable requirement}}
305+
306+
func packingUniqueHeat_2<each T>(_ t: repeat each T)
307+
where repeat each T: ~Copyable {}
308+
// expected-error@-1{{cannot apply inverse '~Copyable' to type 'each T' in conformance requirement}}
309+
// expected-note@-3{{generic parameter 'each T' has an implicit Copyable requirement}}
310+
311+
func packItUniquely() {
312+
packingUniqueHeat_1(MO())
313+
// expected-error@-1{{noncopyable type 'MO' cannot be substituted for copyable generic parameter 'each T' in 'packingUniqueHeat_1'}}
314+
315+
packingUniqueHeat_2(MO())
316+
// expected-error@-1{{noncopyable type 'MO' cannot be substituted for copyable generic parameter 'each T' in 'packingUniqueHeat_2'}}
317+
318+
packingUniqueHeat_1(10)
296319
}

0 commit comments

Comments
 (0)