Skip to content

[NCGenerics] more work towards getting the stdlib building #69842

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5179,6 +5179,10 @@ class ProtocolDecl final : public NominalTypeDecl {
/// semantics but has no corresponding witness table.
bool isMarkerProtocol() const;

/// Determine whether this is an invertible protocol,
/// i.e., for a protocol P, the inverse constraint ~P exists.
bool isInvertibleProtocol() const;

private:
void computeKnownProtocolKind() const;

Expand Down
10 changes: 5 additions & 5 deletions include/swift/AST/ExistentialLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ struct ExistentialLayout {

ExistentialLayout() {
hasExplicitAnyObject = false;
hasInverseCopyable = false;
containsNonObjCProtocol = false;
containsParameterized = false;
representsAnyObject = false;
}

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

/// Whether the existential contains an explicit '& ~Copyable' constraint.
bool hasInverseCopyable : 1;

/// Whether any protocol members are non-@objc.
bool containsNonObjCProtocol : 1;

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

/// Whether this layout is the canonical layout for plain-old 'AnyObject'.
bool representsAnyObject : 1;

/// Return the kind of this existential (class/error/opaque).
Kind getKind() {
if (requiresClass())
Expand All @@ -69,7 +69,7 @@ struct ExistentialLayout {
return Kind::Opaque;
}

bool isAnyObject() const;
bool isAnyObject() const { return representsAnyObject; }

bool isObjC() const {
// FIXME: Does the superclass have to be @objc?
Expand Down
49 changes: 24 additions & 25 deletions include/swift/AST/InverseMarking.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,25 @@
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_LIB_SEMA_INVERSEMARKING_H
#define SWIFT_LIB_SEMA_INVERSEMARKING_H
#ifndef SWIFT_AST_INVERSEMARKING_H
#define SWIFT_AST_INVERSEMARKING_H

#include "swift/AST/KnownProtocols.h"
#include "swift/Basic/SourceLoc.h"
#include "swift/Basic/OptionalEnum.h"

namespace swift {

class NoncopyableAnnotationRequest;

/// Describes the way an inverse and its corresponding positive contraint
/// appears on a TypeDecl, i.e., the way it was marked.
struct InverseMarking {
enum class Kind : uint8_t {
None, // No inverse marking is present
Inferred, // Inverse is inferred based on generic parameters.
Explicit, // Inverse is explicitly present.

LAST = Explicit
LegacyExplicit, // An equivalent, explicit legacy annotation is present.
};

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

// Is there an inferred or explicit marking?
bool isPresent() const {
return getKind() != Kind::None;
}
operator bool() { return isPresent(); }

Kind getKind() const {
return kind.getValueOr(Kind::None);
}
bool is(Kind k) const {
return getKind() == k;
}

// Is there an inferred or explicit marking?
bool isPresent() const {
return !is(Kind::None);
}
operator bool() const { return isPresent(); }

SourceLoc getLoc() const { return loc; }

Expand All @@ -68,34 +72,29 @@ struct InverseMarking {
}

void setIfUnset(Mark other) {
if (kind.hasValue())
if (!other.kind.hasValue())
return;
kind = other.kind;
loc = other.loc;
setIfUnset(other.kind.getValue(), other.loc);
}

Mark with(Kind k) {
kind = k;
return *this;
Mark with(Kind k) const {
return Mark(k, loc);
}
};

private:
Mark inverse;
Mark positive;

// This friend initializes the marks.
friend NoncopyableAnnotationRequest;
public:

// Creates an empty marking.
InverseMarking() {}

Mark &getInverse() { return inverse; }
Mark &getPositive() { return positive; }

// Merge the results of another marking into this one.
void merge(InverseMarking other) const {
other.inverse.setIfUnset(other.inverse);
other.positive.setIfUnset(other.positive);
}
Mark const& getInverse() const { return inverse; }
Mark const& getPositive() const { return positive; }

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

}

#endif //SWIFT_LIB_SEMA_INVERSEMARKING_H
#endif //SWIFT_AST_INVERSEMARKING_H
6 changes: 0 additions & 6 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -5785,8 +5785,6 @@ class ProtocolCompositionType final : public TypeBase,
private llvm::TrailingObjects<ProtocolCompositionType, Type> {
friend TrailingObjects;

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

public:
Expand Down Expand Up @@ -7423,10 +7421,6 @@ inline GenericTypeDecl *TypeBase::getAnyGeneric() {
return getCanonicalType().getAnyGeneric();
}

//inline TypeDecl *TypeBase::getAnyTypeDecl() {
// return getCanonicalType().getAnyTypeDecl();
//}

inline bool TypeBase::isBuiltinIntegerType(unsigned n) {
if (auto intTy = dyn_cast<BuiltinIntegerType>(getCanonicalType()))
return intTy->getWidth().isFixedWidth()
Expand Down
8 changes: 8 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4340,6 +4340,14 @@ namespace {

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

for (auto ip : T->getInverses()) {
switch (ip) {
case InvertibleProtocolKind::Copyable:
printFlag("inverse_copyable");
break;
}
}

for (auto proto : T->getMembers()) {
printRec(proto);
}
Expand Down
96 changes: 75 additions & 21 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericParamList.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/InverseMarking.h"
#include "swift/AST/MacroDefinition.h"
#include "swift/AST/Module.h"
#include "swift/AST/NameLookup.h"
Expand Down Expand Up @@ -3329,33 +3330,66 @@ static bool usesFeatureFlowSensitiveConcurrencyCaptures(Decl *decl) {
return false;
}

static bool usesFeatureMoveOnly(Decl *decl) {
/// \param isRelevantInverse the function used to inspect a mark corresponding
/// to an inverse to determine whether it "has" an inverse that we care about.
static bool hasInverseCopyable(
Decl *decl,
std::function<bool(InverseMarking const&)> isRelevantInverse) {

auto getTypeDecl = [](Type type) -> TypeDecl* {
if (auto genericTy = type->getAnyGeneric())
return genericTy;
if (auto gtpt = dyn_cast<GenericTypeParamType>(type))
return gtpt->getDecl();
return nullptr;
};

if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
if (auto *nominal = extension->getSelfNominalTypeDecl())
if (nominal->canBeNoncopyable())
if (isRelevantInverse(nominal->getNoncopyableMarking()))
return true;
}

if (auto typeDecl = dyn_cast<TypeDecl>(decl)) {
if (typeDecl->canBeNoncopyable())
if (isRelevantInverse(typeDecl->getNoncopyableMarking()))
return true;

// Check the protocol's associated types too.
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
auto hasNoncopyable = llvm::any_of(proto->getAssociatedTypeMembers(),
[&](AssociatedTypeDecl *assocTyDecl) {
return isRelevantInverse(assocTyDecl->getNoncopyableMarking());
});
if (hasNoncopyable)
return true;
}
}

if (auto value = dyn_cast<ValueDecl>(decl)) {
// Check for move-only types in the types of this declaration.
// Check for noncopyable types in the types of this declaration.
if (Type type = value->getInterfaceType()) {
bool hasMoveOnly = type.findIf([](Type type) {
return type->isNoncopyable();
bool hasNoncopyable = type.findIf([&](Type type) {
if (auto *typeDecl = getTypeDecl(type))
if (isRelevantInverse(typeDecl->getNoncopyableMarking()))
return true;

return false;
});

if (hasMoveOnly)
if (hasNoncopyable)
return true;
}
}

return false;
}

static bool usesFeatureMoveOnly(Decl *decl) {
return hasInverseCopyable(decl, [](auto &marking) -> bool {
return marking.getInverse().is(InverseMarking::Kind::LegacyExplicit);
});
}

static bool usesFeatureLazyImmediate(Decl *D) { return false; }

static bool usesFeatureMoveOnlyClasses(Decl *decl) {
Expand Down Expand Up @@ -3393,9 +3427,17 @@ static bool usesFeatureMoveOnlyPartialConsumption(Decl *decl) {
}

static bool usesFeatureNoncopyableGenerics(Decl *decl) {
// FIXME: need to look for suppressed entries on generic parameters or
// inheritance clauses!
return false;
return hasInverseCopyable(decl, [](auto &marking) -> bool {
switch (marking.getInverse().getKind()) {
case InverseMarking::Kind::None:
case InverseMarking::Kind::LegacyExplicit: // covered by MoveOnly
return false;

case InverseMarking::Kind::Explicit:
case InverseMarking::Kind::Inferred:
return true;
}
});
}

static bool usesFeatureOneWayClosureParameters(Decl *decl) {
Expand Down Expand Up @@ -7158,17 +7200,29 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
}

void visitProtocolCompositionType(ProtocolCompositionType *T) {
if (T->getMembers().empty()) {
if (T->hasExplicitAnyObject())
Printer << "AnyObject";
else
Printer.printKeyword("Any", Options);
} else {
interleave(T->getMembers(), [&](Type Ty) { visit(Ty); },
[&] { Printer << " & "; });
if (T->hasExplicitAnyObject())
Printer << " & AnyObject";
}
interleave(T->getMembers(), [&](Type Ty) { visit(Ty); },
[&] { Printer << " & "; });

bool printed = !T->getMembers().empty();
auto printSpecial = [&](llvm::StringRef str, bool tilde=false) {
if (printed)
Printer << " & ";

if (tilde)
Printer << "~";

Printer << str;
printed = true;
};

if (T->hasExplicitAnyObject())
printSpecial("AnyObject");

for (auto ip : T->getInverses())
printSpecial(getProtocolName(getKnownProtocolKind(ip)), true);

if (!printed)
Printer.printKeyword("Any", Options);
}

void visitParameterizedProtocolType(ParameterizedProtocolType *T) {
Expand Down
10 changes: 10 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6383,6 +6383,16 @@ bool ProtocolDecl::isMarkerProtocol() const {
return getAttrs().hasAttribute<MarkerAttr>();
}

bool ProtocolDecl::isInvertibleProtocol() const {
if (auto kp = getKnownProtocolKind()) {
if (getInvertibleProtocolKind(*kp)) {
assert(isMarkerProtocol());
return true;
}
}
return false;
}

ArrayRef<ProtocolDecl *> ProtocolDecl::getInheritedProtocols() const {
auto *mutThis = const_cast<ProtocolDecl *>(this);
return evaluateOrDefault(getASTContext().evaluator,
Expand Down
11 changes: 6 additions & 5 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1591,11 +1591,12 @@ ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
if (!protocol->existentialConformsToSelf())
return ProtocolConformanceRef::forInvalid();

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

auto layout = type->getExistentialLayout();
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/RequirementMachine/RequirementMachineRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,13 @@ AbstractGenericSignatureRequest::evaluate(
requirements.push_back({req, SourceLoc(), /*wasInferred=*/false});
}

/// Next, we need to expand default requirements for the added parameters.
SmallVector<Type, 2> localGPs;
for (auto *gtpt : addedParameters)
localGPs.push_back(gtpt);

expandDefaultRequirements(ctx, localGPs, requirements, errors);

auto &rewriteCtx = ctx.getRewriteContext();

if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {
Expand Down
Loading