Skip to content

Commit 6ca57e3

Browse files
authored
Merge pull request #71488 from kavon/ncgenerics-test-fixes-kavon-v5
Ncgenerics test fixes kavon v5
2 parents c10991a + 5e51773 commit 6ca57e3

File tree

12 files changed

+177
-85
lines changed

12 files changed

+177
-85
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7578,6 +7578,9 @@ ERROR(inverse_with_class_constraint, none,
75787578
"composition involving %select{class requirement %2|'AnyObject'}0 "
75797579
"cannot contain '~%1'",
75807580
(bool, StringRef, Type))
7581+
ERROR(inverse_conflicts_explicit_composition, none,
7582+
"composition cannot contain '~%0' when another member requires '%0'",
7583+
(StringRef))
75817584
ERROR(inverse_extension, none,
75827585
"cannot apply inverse %0 to extension",
75837586
(Type))

include/swift/AST/Requirement.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,15 +255,26 @@ struct InverseRequirement {
255255
static void enumerateDefaultedParams(GenericContext *decl,
256256
SmallVectorImpl<Type> &result);
257257

258-
/// \returns the protocols that are required by default for the given type
259-
/// parameter. These are not inverses themselves.
260-
static InvertibleProtocolSet expandDefault(Type gp);
261-
262258
/// Appends additional requirements corresponding to defaults for the given
263259
/// generic parameters.
264260
static void expandDefaults(ASTContext &ctx,
265261
ArrayRef<Type> gps,
266262
SmallVectorImpl<StructuralRequirement> &result);
263+
264+
/// Adds the inferred default protocols for an assumed generic parameter with
265+
/// respect to that parameter's inverses and existing required protocols.
266+
/// For example, if an inverse ~P exists, then P will not be added to the
267+
/// protocols list.
268+
///
269+
/// Similarly, if the protocols list has a protocol Q that already implies
270+
/// Copyable, then we will not add `Copyable` to the protocols list.
271+
///
272+
/// \param inverses the inverses '& ~P' that are applied to the generic param.
273+
/// \param protocols the existing required protocols, to which defaults will
274+
/// be appended.
275+
static void expandDefaults(ASTContext &ctx,
276+
InvertibleProtocolSet inverses,
277+
SmallVectorImpl<ProtocolDecl*> &protocols);
267278
};
268279

269280
} // end namespace swift

lib/AST/Requirement.cpp

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -342,27 +342,64 @@ void InverseRequirement::enumerateDefaultedParams(
342342
add(gtpd->getDeclaredInterfaceType());
343343
}
344344

345-
InvertibleProtocolSet InverseRequirement::expandDefault(Type gp) {
346-
assert(gp->isTypeParameter());
347-
return InvertibleProtocolSet::full();
348-
}
349-
350345
void InverseRequirement::expandDefaults(
351346
ASTContext &ctx,
352347
ArrayRef<Type> gps,
353348
SmallVectorImpl<StructuralRequirement> &result) {
354-
if (!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics))
349+
350+
SmallVector<ProtocolDecl*, NumInvertibleProtocols> defaults;
351+
expandDefaults(ctx, /*inverses=*/{}, defaults);
352+
353+
// Fast-path.
354+
if (defaults.empty())
355355
return;
356356

357357
for (auto gp : gps) {
358-
auto protos = InverseRequirement::expandDefault(gp);
359-
for (auto ip : protos) {
360-
auto proto = ctx.getProtocol(getKnownProtocolKind(ip));
361-
assert(proto && "missing Copyable/Escapable from stdlib!");
362-
358+
for (auto *proto : defaults) {
363359
auto protoTy = proto->getDeclaredInterfaceType();
364360
result.push_back({{RequirementKind::Conformance, gp, protoTy},
365361
SourceLoc()});
366362
}
367363
}
368364
}
365+
366+
void InverseRequirement::expandDefaults(
367+
ASTContext &ctx,
368+
InvertibleProtocolSet inverses,
369+
SmallVectorImpl<ProtocolDecl*> &protocols) {
370+
371+
// Skip unless noncopyable generics is enabled
372+
if (!ctx.LangOpts.hasFeature(swift::Feature::NoncopyableGenerics))
373+
return;
374+
375+
// Try to add all invertible protocols, unless:
376+
// - an inverse was provided
377+
// - an existing protocol already requires it
378+
for (auto ip : InvertibleProtocolSet::full()) {
379+
// This matches with `lookupExistentialConformance`'s use of 'inheritsFrom'.
380+
bool alreadyRequired = false;
381+
for (auto proto : protocols) {
382+
if (proto->isSpecificProtocol(getKnownProtocolKind(ip))
383+
|| proto->requiresInvertible(ip)) {
384+
alreadyRequired = true;
385+
break;
386+
}
387+
}
388+
389+
// If some protocol member already implies P, then we don't need to
390+
// add a requirement for P.
391+
if (alreadyRequired) {
392+
assert(!inverses.contains(ip) && "cannot require P and ~P");
393+
continue;
394+
}
395+
396+
// Nothing implies P, so unless there's an inverse ~P, add the requirement.
397+
if (inverses.contains(ip))
398+
continue;
399+
400+
auto proto = ctx.getProtocol(getKnownProtocolKind(ip));
401+
assert(proto && "missing Copyable/Escapable from stdlib!");
402+
403+
protocols.push_back(proto);
404+
}
405+
}

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -926,8 +926,11 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
926926
SourceLoc()});
927927

928928
desugarRequirements(result, inverses, errors);
929-
InverseRequirement::expandDefaults(ctx, needsDefaultRequirements, result);
930-
applyInverses(ctx, needsDefaultRequirements, inverses, result, errors);
929+
930+
SmallVector<StructuralRequirement, 2> defaults;
931+
InverseRequirement::expandDefaults(ctx, needsDefaultRequirements, defaults);
932+
applyInverses(ctx, needsDefaultRequirements, inverses, defaults, errors);
933+
result.append(defaults);
931934

932935
diagnoseRequirementErrors(ctx, errors,
933936
AllowConcreteTypePolicy::NestedAssocTypes);
@@ -994,11 +997,13 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
994997

995998
desugarRequirements(result, inverses, errors);
996999

1000+
SmallVector<StructuralRequirement, 2> defaults;
9971001
// We do not expand defaults for invertible protocols themselves.
9981002
if (!proto->getInvertibleProtocolKind())
999-
InverseRequirement::expandDefaults(ctx, needsDefaultRequirements, result);
1003+
InverseRequirement::expandDefaults(ctx, needsDefaultRequirements, defaults);
10001004

1001-
applyInverses(ctx, needsDefaultRequirements, inverses, result, errors);
1005+
applyInverses(ctx, needsDefaultRequirements, inverses, defaults, errors);
1006+
result.append(defaults);
10021007

10031008
diagnoseRequirementErrors(ctx, errors,
10041009
AllowConcreteTypePolicy::NestedAssocTypes);

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -667,8 +667,10 @@ AbstractGenericSignatureRequest::evaluate(
667667
paramsAsTypes.push_back(gtpt);
668668
}
669669

670-
InverseRequirement::expandDefaults(ctx, paramsAsTypes, requirements);
671-
applyInverses(ctx, paramsAsTypes, inverses, requirements, errors);
670+
SmallVector<StructuralRequirement, 2> defaults;
671+
InverseRequirement::expandDefaults(ctx, paramsAsTypes, defaults);
672+
applyInverses(ctx, paramsAsTypes, inverses, defaults, errors);
673+
requirements.append(defaults);
672674

673675
auto &rewriteCtx = ctx.getRewriteContext();
674676

@@ -882,8 +884,10 @@ InferredGenericSignatureRequest::evaluate(
882884
paramTypes.append(genericParams.begin() + numOuterParams, genericParams.end());
883885
}
884886

885-
InverseRequirement::expandDefaults(ctx, paramTypes, requirements);
886-
applyInverses(ctx, paramTypes, inverses, requirements, errors);
887+
SmallVector<StructuralRequirement, 2> defaults;
888+
InverseRequirement::expandDefaults(ctx, paramTypes, defaults);
889+
applyInverses(ctx, paramTypes, inverses, defaults, errors);
890+
requirements.append(defaults);
887891

888892
auto &rewriteCtx = ctx.getRewriteContext();
889893

lib/AST/Type.cpp

Lines changed: 12 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -278,50 +278,7 @@ bool TypeBase::allowsOwnership(const GenericSignatureImpl *sig) {
278278
return getCanonicalType().allowsOwnership(sig);
279279
}
280280

281-
/// Adds the inferred default protocols for an ExistentialLayout with respect
282-
/// to that existential's inverses and existing protocols. For example, if an
283-
/// inverse ~P exists, then P will not be added to the protocols list.
284-
///
285-
/// Similarly, if the protocols list has a protocol Q that already implies
286-
/// Copyable, then we will not add `Copyable` to the protocols list.
287-
///
288-
/// \param inverses the inverses '& ~P' that are in the existential's type.
289-
/// \param protocols the output vector of protocols for an ExistentialLayout
290-
/// to be modified.
291-
static void expandDefaultProtocols(
292-
ASTContext &ctx,
293-
InvertibleProtocolSet inverses,
294-
SmallVectorImpl<ProtocolDecl*> &protocols) {
295-
296-
// Skip unless noncopyable generics is enabled
297-
if (!ctx.LangOpts.hasFeature(swift::Feature::NoncopyableGenerics))
298-
return;
299281

300-
// Try to add all invertible protocols, unless:
301-
// - an inverse was provided
302-
// - an existing protocol already requires it
303-
for (auto ip : InvertibleProtocolSet::full()) {
304-
if (inverses.contains(ip))
305-
continue;
306-
307-
// This matches with `lookupExistentialConformance`'s use of 'inheritsFrom'.
308-
bool alreadyRequired = false;
309-
for (auto proto : protocols) {
310-
if (proto->requiresInvertible(ip)) {
311-
alreadyRequired = true;
312-
break;
313-
}
314-
}
315-
316-
if (alreadyRequired)
317-
continue;
318-
319-
auto proto = ctx.getProtocol(getKnownProtocolKind(ip));
320-
assert(proto && "missing Copyable/Escapable from stdlib!");
321-
322-
protocols.push_back(proto);
323-
}
324-
}
325282

326283
ExistentialLayout::ExistentialLayout(CanProtocolType type) {
327284
auto *protoDecl = type->getDecl();
@@ -336,7 +293,7 @@ ExistentialLayout::ExistentialLayout(CanProtocolType type) {
336293
protocols.push_back(protoDecl);
337294

338295
// NOTE: all the invertible protocols are usable from ObjC.
339-
expandDefaultProtocols(type->getASTContext(), {}, protocols);
296+
InverseRequirement::expandDefaults(type->getASTContext(), {}, protocols);
340297
}
341298

342299
ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) {
@@ -373,7 +330,9 @@ ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) {
373330
hasExplicitAnyObject && !explicitSuperclass && getProtocols().empty();
374331

375332
// NOTE: all the invertible protocols are usable from ObjC.
376-
expandDefaultProtocols(type->getASTContext(), type->getInverses(), protocols);
333+
InverseRequirement::expandDefaults(type->getASTContext(),
334+
type->getInverses(),
335+
protocols);
377336
}
378337

379338
ExistentialLayout::ExistentialLayout(CanParameterizedProtocolType type)
@@ -3939,7 +3898,7 @@ Type ProtocolCompositionType::get(const ASTContext &C,
39393898
ArrayRef<Type> Members,
39403899
InvertibleProtocolSet Inverses,
39413900
bool HasExplicitAnyObject) {
3942-
// Fast path for 'AnyObject' and 'Any'.
3901+
// Fast path for 'AnyObject', 'Any', and '~Copyable'.
39433902
if (Members.empty()) {
39443903
return build(C, Members, Inverses, HasExplicitAnyObject);
39453904
}
@@ -3994,6 +3953,13 @@ Type ProtocolCompositionType::get(const ASTContext &C,
39943953
}
39953954
}
39963955

3956+
// Drop any explicitly provided invertible protocols.
3957+
if (auto ip = proto->getInvertibleProtocolKind()) {
3958+
// We diagnose '~Copyable & Copyable' before forming the PCT.
3959+
assert(!Inverses.contains(*ip) && "opposing invertible constraints!");
3960+
continue;
3961+
}
3962+
39973963
CanTypes.push_back(proto->getDeclaredInterfaceType());
39983964
}
39993965

lib/Basic/LangOptions.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ LangOptions::LangOptions() {
4747
#endif
4848

4949
// Note: Introduce default-on language options here.
50+
51+
// Default-on NoncopyableGenerics when the build-script setting is enabled.
52+
if (SWIFT_ENABLE_EXPERIMENTAL_NONCOPYABLE_GENERICS) {
53+
Features.insert(Feature::NoncopyableGenerics);
54+
EnableExperimentalAssociatedTypeInference = true;
55+
}
56+
5057
// Enable any playground options that are enabled by default.
5158
#define PLAYGROUND_OPTION(OptionName, Description, DefaultOn, HighPerfOn) \
5259
if (DefaultOn) \

lib/DriverTool/sil_opt_main.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -645,8 +645,6 @@ int sil_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
645645
Invocation.getLangOptions().enableFeature(
646646
Feature::OldOwnershipOperatorSpellings);
647647
}
648-
if (SWIFT_ENABLE_EXPERIMENTAL_NONCOPYABLE_GENERICS)
649-
Invocation.getLangOptions().enableFeature(Feature::NoncopyableGenerics);
650648

651649
Invocation.getLangOptions().BypassResilienceChecks =
652650
options.BypassResilienceChecks;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -895,11 +895,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
895895

896896
Opts.enableFeature(Feature::LayoutPrespecialization);
897897

898-
if (SWIFT_ENABLE_EXPERIMENTAL_NONCOPYABLE_GENERICS) {
899-
Opts.enableFeature(Feature::NoncopyableGenerics);
900-
Opts.EnableExperimentalAssociatedTypeInference = true;
901-
}
902-
903898
Opts.EnableAppExtensionLibraryRestrictions |= Args.hasArg(OPT_enable_app_extension_library);
904899
Opts.EnableAppExtensionRestrictions |= Args.hasArg(OPT_enable_app_extension);
905900
Opts.EnableAppExtensionRestrictions |= Opts.EnableAppExtensionLibraryRestrictions;

lib/Sema/TypeCheckType.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5401,6 +5401,46 @@ NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr,
54015401
return TupleType::get(elements, ctx);
54025402
}
54035403

5404+
/// \returns the inverse ~P that is conflicted if a protocol in \c tys
5405+
/// requires P. For example, `Q & ~Copyable` is a conflict, if `Q` requires
5406+
/// or is equal to `Copyable`
5407+
static std::optional<InvertibleProtocolKind>
5408+
hasConflictedInverse(ArrayRef<Type> tys, InvertibleProtocolSet inverses) {
5409+
// Fast-path: no inverses that could be conflicted!
5410+
if (inverses.empty())
5411+
return std::nullopt;
5412+
5413+
for (auto ty : tys) {
5414+
// Handle nested PCT's recursively since we haven't flattened them away yet.
5415+
if (auto pct = dyn_cast<ProtocolCompositionType>(ty)) {
5416+
if (auto conflict = hasConflictedInverse(pct->getMembers(), inverses))
5417+
return conflict;
5418+
continue;
5419+
}
5420+
5421+
// Dig out a protocol.
5422+
ProtocolDecl *decl = nullptr;
5423+
if (auto protoTy = dyn_cast<ProtocolType>(ty))
5424+
decl = protoTy->getDecl();
5425+
else if (auto paramProtoTy = dyn_cast<ParameterizedProtocolType>(ty))
5426+
decl = paramProtoTy->getProtocol();
5427+
5428+
if (!decl)
5429+
continue;
5430+
5431+
// If an inverse ~I exists for this protocol member of the PCT that
5432+
// requires I, then it's a conflict.
5433+
for (auto inverse : inverses) {
5434+
if (decl->isSpecificProtocol(getKnownProtocolKind(inverse))
5435+
|| decl->requiresInvertible(inverse)) {
5436+
return inverse;
5437+
}
5438+
}
5439+
}
5440+
5441+
return std::nullopt;
5442+
}
5443+
54045444
NeverNullType
54055445
TypeResolver::resolveCompositionType(CompositionTypeRepr *repr,
54065446
TypeResolutionOptions options) {
@@ -5496,6 +5536,13 @@ TypeResolver::resolveCompositionType(CompositionTypeRepr *repr,
54965536
IsInvalid = true;
54975537
}
54985538

5539+
// Cannot provide an inverse in the same composition requiring the protocol.
5540+
if (auto conflict = hasConflictedInverse(Members, Inverses)) {
5541+
diagnose(repr->getLoc(),
5542+
diag::inverse_conflicts_explicit_composition,
5543+
getProtocolName(getKnownProtocolKind(*conflict)));
5544+
IsInvalid = true;
5545+
}
54995546

55005547
if (IsInvalid) {
55015548
repr->setInvalid();

0 commit comments

Comments
 (0)