Skip to content

Commit 81ea998

Browse files
authored
Merge pull request #69842 from kavon/ncgenerics-stdlib-building
[NCGenerics] more work towards getting the stdlib building
2 parents 1c0971e + eff3255 commit 81ea998

18 files changed

+328
-138
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5215,6 +5215,10 @@ class ProtocolDecl final : public NominalTypeDecl {
52155215
/// semantics but has no corresponding witness table.
52165216
bool isMarkerProtocol() const;
52175217

5218+
/// Determine whether this is an invertible protocol,
5219+
/// i.e., for a protocol P, the inverse constraint ~P exists.
5220+
bool isInvertibleProtocol() const;
5221+
52185222
private:
52195223
void computeKnownProtocolKind() const;
52205224

include/swift/AST/ExistentialLayout.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ struct ExistentialLayout {
3131

3232
ExistentialLayout() {
3333
hasExplicitAnyObject = false;
34-
hasInverseCopyable = false;
3534
containsNonObjCProtocol = false;
3635
containsParameterized = false;
36+
representsAnyObject = false;
3737
}
3838

3939
ExistentialLayout(CanProtocolType type);
@@ -47,15 +47,15 @@ struct ExistentialLayout {
4747
/// Whether the existential contains an explicit '& AnyObject' constraint.
4848
bool hasExplicitAnyObject : 1;
4949

50-
/// Whether the existential contains an explicit '& ~Copyable' constraint.
51-
bool hasInverseCopyable : 1;
52-
5350
/// Whether any protocol members are non-@objc.
5451
bool containsNonObjCProtocol : 1;
5552

5653
/// Whether any protocol members are parameterized.s
5754
bool containsParameterized : 1;
5855

56+
/// Whether this layout is the canonical layout for plain-old 'AnyObject'.
57+
bool representsAnyObject : 1;
58+
5959
/// Return the kind of this existential (class/error/opaque).
6060
Kind getKind() {
6161
if (requiresClass())
@@ -69,7 +69,7 @@ struct ExistentialLayout {
6969
return Kind::Opaque;
7070
}
7171

72-
bool isAnyObject() const;
72+
bool isAnyObject() const { return representsAnyObject; }
7373

7474
bool isObjC() const {
7575
// FIXME: Does the superclass have to be @objc?

include/swift/AST/InverseMarking.h

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,25 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#ifndef SWIFT_LIB_SEMA_INVERSEMARKING_H
14-
#define SWIFT_LIB_SEMA_INVERSEMARKING_H
13+
#ifndef SWIFT_AST_INVERSEMARKING_H
14+
#define SWIFT_AST_INVERSEMARKING_H
1515

1616
#include "swift/AST/KnownProtocols.h"
1717
#include "swift/Basic/SourceLoc.h"
1818
#include "swift/Basic/OptionalEnum.h"
1919

2020
namespace swift {
2121

22+
class NoncopyableAnnotationRequest;
23+
2224
/// Describes the way an inverse and its corresponding positive contraint
2325
/// appears on a TypeDecl, i.e., the way it was marked.
2426
struct InverseMarking {
2527
enum class Kind : uint8_t {
2628
None, // No inverse marking is present
2729
Inferred, // Inverse is inferred based on generic parameters.
2830
Explicit, // Inverse is explicitly present.
29-
30-
LAST = Explicit
31+
LegacyExplicit, // An equivalent, explicit legacy annotation is present.
3132
};
3233

3334
// Describes what kind of mark was found, if any.
@@ -43,15 +44,18 @@ struct InverseMarking {
4344
Mark(Kind k, SourceLoc l = SourceLoc())
4445
: kind(k), loc(l) {};
4546

46-
// Is there an inferred or explicit marking?
47-
bool isPresent() const {
48-
return getKind() != Kind::None;
49-
}
50-
operator bool() { return isPresent(); }
51-
5247
Kind getKind() const {
5348
return kind.getValueOr(Kind::None);
5449
}
50+
bool is(Kind k) const {
51+
return getKind() == k;
52+
}
53+
54+
// Is there an inferred or explicit marking?
55+
bool isPresent() const {
56+
return !is(Kind::None);
57+
}
58+
operator bool() const { return isPresent(); }
5559

5660
SourceLoc getLoc() const { return loc; }
5761

@@ -68,34 +72,29 @@ struct InverseMarking {
6872
}
6973

7074
void setIfUnset(Mark other) {
71-
if (kind.hasValue())
75+
if (!other.kind.hasValue())
7276
return;
73-
kind = other.kind;
74-
loc = other.loc;
77+
setIfUnset(other.kind.getValue(), other.loc);
7578
}
7679

77-
Mark with(Kind k) {
78-
kind = k;
79-
return *this;
80+
Mark with(Kind k) const {
81+
return Mark(k, loc);
8082
}
8183
};
8284

8385
private:
8486
Mark inverse;
8587
Mark positive;
88+
89+
// This friend initializes the marks.
90+
friend NoncopyableAnnotationRequest;
8691
public:
8792

8893
// Creates an empty marking.
8994
InverseMarking() {}
9095

91-
Mark &getInverse() { return inverse; }
92-
Mark &getPositive() { return positive; }
93-
94-
// Merge the results of another marking into this one.
95-
void merge(InverseMarking other) const {
96-
other.inverse.setIfUnset(other.inverse);
97-
other.positive.setIfUnset(other.positive);
98-
}
96+
Mark const& getInverse() const { return inverse; }
97+
Mark const& getPositive() const { return positive; }
9998

10099
static InverseMarking forInverse(Kind kind, SourceLoc loc = SourceLoc()) {
101100
InverseMarking marking;
@@ -107,4 +106,4 @@ struct InverseMarking {
107106

108107
}
109108

110-
#endif //SWIFT_LIB_SEMA_INVERSEMARKING_H
109+
#endif //SWIFT_AST_INVERSEMARKING_H

include/swift/AST/Types.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5783,8 +5783,6 @@ class ProtocolCompositionType final : public TypeBase,
57835783
private llvm::TrailingObjects<ProtocolCompositionType, Type> {
57845784
friend TrailingObjects;
57855785

5786-
// TODO(kavon): this could probably be folded into the existing Bits field
5787-
// or we could just store the InverseType's in the Members array.
57885786
InvertibleProtocolSet Inverses;
57895787

57905788
public:
@@ -7421,10 +7419,6 @@ inline GenericTypeDecl *TypeBase::getAnyGeneric() {
74217419
return getCanonicalType().getAnyGeneric();
74227420
}
74237421

7424-
//inline TypeDecl *TypeBase::getAnyTypeDecl() {
7425-
// return getCanonicalType().getAnyTypeDecl();
7426-
//}
7427-
74287422
inline bool TypeBase::isBuiltinIntegerType(unsigned n) {
74297423
if (auto intTy = dyn_cast<BuiltinIntegerType>(getCanonicalType()))
74307424
return intTy->getWidth().isFixedWidth()

lib/AST/ASTDumper.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4336,6 +4336,14 @@ namespace {
43364336

43374337
printFlag(T->hasExplicitAnyObject(), "any_object");
43384338

4339+
for (auto ip : T->getInverses()) {
4340+
switch (ip) {
4341+
case InvertibleProtocolKind::Copyable:
4342+
printFlag("inverse_copyable");
4343+
break;
4344+
}
4345+
}
4346+
43394347
for (auto proto : T->getMembers()) {
43404348
printRec(proto);
43414349
}

lib/AST/ASTPrinter.cpp

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "swift/AST/GenericEnvironment.h"
3030
#include "swift/AST/GenericParamList.h"
3131
#include "swift/AST/GenericSignature.h"
32+
#include "swift/AST/InverseMarking.h"
3233
#include "swift/AST/MacroDefinition.h"
3334
#include "swift/AST/Module.h"
3435
#include "swift/AST/NameLookup.h"
@@ -3360,33 +3361,66 @@ static bool usesFeatureFlowSensitiveConcurrencyCaptures(Decl *decl) {
33603361
return false;
33613362
}
33623363

3363-
static bool usesFeatureMoveOnly(Decl *decl) {
3364+
/// \param isRelevantInverse the function used to inspect a mark corresponding
3365+
/// to an inverse to determine whether it "has" an inverse that we care about.
3366+
static bool hasInverseCopyable(
3367+
Decl *decl,
3368+
std::function<bool(InverseMarking const&)> isRelevantInverse) {
3369+
3370+
auto getTypeDecl = [](Type type) -> TypeDecl* {
3371+
if (auto genericTy = type->getAnyGeneric())
3372+
return genericTy;
3373+
if (auto gtpt = dyn_cast<GenericTypeParamType>(type))
3374+
return gtpt->getDecl();
3375+
return nullptr;
3376+
};
3377+
33643378
if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
33653379
if (auto *nominal = extension->getSelfNominalTypeDecl())
3366-
if (nominal->canBeNoncopyable())
3380+
if (isRelevantInverse(nominal->getNoncopyableMarking()))
33673381
return true;
33683382
}
33693383

33703384
if (auto typeDecl = dyn_cast<TypeDecl>(decl)) {
3371-
if (typeDecl->canBeNoncopyable())
3385+
if (isRelevantInverse(typeDecl->getNoncopyableMarking()))
33723386
return true;
3387+
3388+
// Check the protocol's associated types too.
3389+
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
3390+
auto hasNoncopyable = llvm::any_of(proto->getAssociatedTypeMembers(),
3391+
[&](AssociatedTypeDecl *assocTyDecl) {
3392+
return isRelevantInverse(assocTyDecl->getNoncopyableMarking());
3393+
});
3394+
if (hasNoncopyable)
3395+
return true;
3396+
}
33733397
}
33743398

33753399
if (auto value = dyn_cast<ValueDecl>(decl)) {
3376-
// Check for move-only types in the types of this declaration.
3400+
// Check for noncopyable types in the types of this declaration.
33773401
if (Type type = value->getInterfaceType()) {
3378-
bool hasMoveOnly = type.findIf([](Type type) {
3379-
return type->isNoncopyable();
3402+
bool hasNoncopyable = type.findIf([&](Type type) {
3403+
if (auto *typeDecl = getTypeDecl(type))
3404+
if (isRelevantInverse(typeDecl->getNoncopyableMarking()))
3405+
return true;
3406+
3407+
return false;
33803408
});
33813409

3382-
if (hasMoveOnly)
3410+
if (hasNoncopyable)
33833411
return true;
33843412
}
33853413
}
33863414

33873415
return false;
33883416
}
33893417

3418+
static bool usesFeatureMoveOnly(Decl *decl) {
3419+
return hasInverseCopyable(decl, [](auto &marking) -> bool {
3420+
return marking.getInverse().is(InverseMarking::Kind::LegacyExplicit);
3421+
});
3422+
}
3423+
33903424
static bool usesFeatureLazyImmediate(Decl *D) { return false; }
33913425

33923426
static bool usesFeatureMoveOnlyClasses(Decl *decl) {
@@ -3424,9 +3458,17 @@ static bool usesFeatureMoveOnlyPartialConsumption(Decl *decl) {
34243458
}
34253459

34263460
static bool usesFeatureNoncopyableGenerics(Decl *decl) {
3427-
// FIXME: need to look for suppressed entries on generic parameters or
3428-
// inheritance clauses!
3429-
return false;
3461+
return hasInverseCopyable(decl, [](auto &marking) -> bool {
3462+
switch (marking.getInverse().getKind()) {
3463+
case InverseMarking::Kind::None:
3464+
case InverseMarking::Kind::LegacyExplicit: // covered by MoveOnly
3465+
return false;
3466+
3467+
case InverseMarking::Kind::Explicit:
3468+
case InverseMarking::Kind::Inferred:
3469+
return true;
3470+
}
3471+
});
34303472
}
34313473

34323474
static bool usesFeatureOneWayClosureParameters(Decl *decl) {
@@ -7207,17 +7249,29 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
72077249
}
72087250

72097251
void visitProtocolCompositionType(ProtocolCompositionType *T) {
7210-
if (T->getMembers().empty()) {
7211-
if (T->hasExplicitAnyObject())
7212-
Printer << "AnyObject";
7213-
else
7214-
Printer.printKeyword("Any", Options);
7215-
} else {
7216-
interleave(T->getMembers(), [&](Type Ty) { visit(Ty); },
7217-
[&] { Printer << " & "; });
7218-
if (T->hasExplicitAnyObject())
7219-
Printer << " & AnyObject";
7220-
}
7252+
interleave(T->getMembers(), [&](Type Ty) { visit(Ty); },
7253+
[&] { Printer << " & "; });
7254+
7255+
bool printed = !T->getMembers().empty();
7256+
auto printSpecial = [&](llvm::StringRef str, bool tilde=false) {
7257+
if (printed)
7258+
Printer << " & ";
7259+
7260+
if (tilde)
7261+
Printer << "~";
7262+
7263+
Printer << str;
7264+
printed = true;
7265+
};
7266+
7267+
if (T->hasExplicitAnyObject())
7268+
printSpecial("AnyObject");
7269+
7270+
for (auto ip : T->getInverses())
7271+
printSpecial(getProtocolName(getKnownProtocolKind(ip)), true);
7272+
7273+
if (!printed)
7274+
Printer.printKeyword("Any", Options);
72217275
}
72227276

72237277
void visitParameterizedProtocolType(ParameterizedProtocolType *T) {

lib/AST/Decl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6394,6 +6394,16 @@ bool ProtocolDecl::isMarkerProtocol() const {
63946394
return getAttrs().hasAttribute<MarkerAttr>();
63956395
}
63966396

6397+
bool ProtocolDecl::isInvertibleProtocol() const {
6398+
if (auto kp = getKnownProtocolKind()) {
6399+
if (getInvertibleProtocolKind(*kp)) {
6400+
assert(isMarkerProtocol());
6401+
return true;
6402+
}
6403+
}
6404+
return false;
6405+
}
6406+
63976407
ArrayRef<ProtocolDecl *> ProtocolDecl::getInheritedProtocols() const {
63986408
auto *mutThis = const_cast<ProtocolDecl *>(this);
63996409
return evaluateOrDefault(getASTContext().evaluator,

lib/AST/Module.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,11 +1568,12 @@ ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
15681568
if (!protocol->existentialConformsToSelf())
15691569
return ProtocolConformanceRef::forInvalid();
15701570

1571-
// All existentials are Copyable.
1572-
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
1573-
return ProtocolConformanceRef(
1574-
ctx.getBuiltinConformance(type, protocol,
1575-
BuiltinConformanceKind::Synthesized));
1571+
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)
1572+
&& !ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
1573+
// Prior to noncopyable generics, all existentials conform to Copyable.
1574+
return ProtocolConformanceRef(
1575+
ctx.getBuiltinConformance(type, protocol,
1576+
BuiltinConformanceKind::Synthesized));
15761577
}
15771578

15781579
auto layout = type->getExistentialLayout();

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,13 @@ AbstractGenericSignatureRequest::evaluate(
653653
SmallVector<RequirementError, 2> errors;
654654
desugarRequirements(requirements, errors);
655655

656+
/// Next, we need to expand default requirements for the added parameters.
657+
SmallVector<Type, 2> localGPs;
658+
for (auto *gtpt : addedParameters)
659+
localGPs.push_back(gtpt);
660+
661+
expandDefaultRequirements(ctx, localGPs, requirements, errors);
662+
656663
auto &rewriteCtx = ctx.getRewriteContext();
657664

658665
if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {

0 commit comments

Comments
 (0)