Skip to content

Copyable as a Requirement Against the Machine #67930

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 5 commits into from
Sep 21, 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/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2349,6 +2349,10 @@ ERROR(inferred_opaque_type,none,
"property definition has inferred type %0, involving the 'some' "
"return type of another declaration", (Type))

// Inverse Constraints
ERROR(inverse_type_not_invertable,none,
"type %0 is not invertable", (Type))

// Extensions
ERROR(non_nominal_extension,none,
"non-nominal type %0 cannot be extended", (Type))
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/KnownProtocols.def
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ PROTOCOL(AsyncIteratorProtocol)

PROTOCOL(FloatingPoint)

PROTOCOL_(Copyable)
PROTOCOL(Copyable)

EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByArrayLiteral, "Array", false)
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByBooleanLiteral, "BooleanLiteralType", true)
Expand Down
7 changes: 7 additions & 0 deletions include/swift/AST/KnownProtocols.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define SWIFT_AST_KNOWNPROTOCOLS_H

#include "swift/Basic/InlineBitfield.h"
#include "swift/Basic/FixedBitSet.h"
#include "swift/Config.h"

namespace llvm {
Expand Down Expand Up @@ -41,6 +42,12 @@ enum : uint8_t {
enum : unsigned { NumKnownProtocolKindBits =
countBitsUsed(static_cast<unsigned>(NumKnownProtocols - 1)) };

using KnownProtocolSet = FixedBitSet<NumKnownProtocols, KnownProtocolKind>;

/// Produces a set of all protocols that have an inverse, i.e., for every
/// known protocol KP in the set, ~KP exists.
KnownProtocolSet getInvertableProtocols();

/// Retrieve the name of the given known protocol.
llvm::StringRef getProtocolName(KnownProtocolKind kind);

Expand Down
29 changes: 29 additions & 0 deletions include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,34 @@ class ExistentialTypeRepr: public TypeRepr {
friend class TypeRepr;
};

/// A type repr represeting the inverse of some constraint. For example,
/// ~Copyable
/// where `Copyable` is the constraint type.
class InverseTypeRepr : public TypeRepr {
TypeRepr *Constraint;
SourceLoc TildeLoc;

public:
InverseTypeRepr(SourceLoc tildeLoc, TypeRepr *constraint)
: TypeRepr(TypeReprKind::Inverse), Constraint(constraint),
TildeLoc(tildeLoc) {}

TypeRepr *getConstraint() const { return Constraint; }
SourceLoc getTildeLoc() const { return TildeLoc; }

static bool classof(const TypeRepr *T) {
return T->getKind() == TypeReprKind::Inverse;
}
static bool classof(const InverseTypeRepr *T) { return true; }

private:
SourceLoc getStartLocImpl() const { return TildeLoc; }
SourceLoc getEndLocImpl() const { return Constraint->getEndLoc(); }
SourceLoc getLocImpl() const { return TildeLoc; }
void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const;
friend class TypeRepr;
};

/// TypeRepr for a user-specified placeholder (essentially, a user-facing
/// representation of an anonymous type variable.
///
Expand Down Expand Up @@ -1459,6 +1487,7 @@ inline bool TypeRepr::isSimple() const {
case TypeReprKind::Dictionary:
case TypeReprKind::Optional:
case TypeReprKind::ImplicitlyUnwrappedOptional:
case TypeReprKind::Inverse:
case TypeReprKind::Vararg:
case TypeReprKind::PackExpansion:
case TypeReprKind::Pack:
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/TypeReprNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ TYPEREPR(Protocol, TypeRepr)
TYPEREPR(OpaqueReturn, TypeRepr)
TYPEREPR(NamedOpaqueReturn, TypeRepr)
TYPEREPR(Existential, TypeRepr)
TYPEREPR(Inverse, TypeRepr)
TYPEREPR(Pack, TypeRepr)
TYPEREPR(PackElement, TypeRepr)
TYPEREPR(Placeholder, TypeRepr)
Expand Down
6 changes: 3 additions & 3 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,8 @@ class alignas(1 << TypeAlignInBits) TypeBase

bool isPlaceholder();

/// Returns true if this is a move-only type.
bool isPureMoveOnly();
/// Returns true if this is a noncopyable type.
bool isNoncopyable();

/// Does the type have outer parenthesis?
bool hasParenSugar() const { return getKind() == TypeKind::Paren; }
Expand Down Expand Up @@ -5351,7 +5351,7 @@ class SILMoveOnlyWrappedType final : public TypeBase,
: TypeBase(TypeKind::SILMoveOnlyWrapped, &innerType->getASTContext(),
innerType->getRecursiveProperties()),
innerType(innerType) {
assert(!innerType->isPureMoveOnly() && "Inner type must be copyable");
assert(!innerType->isNoncopyable() && "Inner type must be copyable");
}

public:
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ EXPERIMENTAL_FEATURE(RawLayout, true)
/// Enables the "embedded" swift mode (no runtime).
EXPERIMENTAL_FEATURE(Embedded, true)

/// Enables noncopyable generics
EXPERIMENTAL_FEATURE(NoncopyableGenerics, false)

#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
#undef EXPERIMENTAL_FEATURE
#undef UPCOMING_FEATURE
Expand Down
10 changes: 10 additions & 0 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ class Parser {
bool InSwiftKeyPath = false;
bool InFreestandingMacroArgument = false;

// A cached answer to
// Context.LangOpts.hasFeature(Feature::NoncopyableGenerics)
// to ensure there's no parsing performance regression.
bool EnabledNoncopyableGenerics;

/// Whether we should delay parsing nominal type, extension, and function
/// bodies.
bool isDelayedParsingEnabled() const;
Expand Down Expand Up @@ -2058,6 +2063,11 @@ class Parser {

void performIDEInspectionSecondPassImpl(
IDEInspectionDelayedDeclState &info);

/// Returns true if the caller should skip calling `parseType` afterwards.
bool parseLegacyTildeCopyable(SourceLoc *parseTildeCopyable,
ParserStatus &Status,
SourceLoc &TildeCopyableLoc);
};

/// Describes a parsed declaration name.
Expand Down
4 changes: 0 additions & 4 deletions include/swift/SIL/SILType.h
Original file line number Diff line number Diff line change
Expand Up @@ -748,10 +748,6 @@ class SILType {
/// wrapped type.
bool isMoveOnly() const;

/// Is this a type that is a first class move only type. This returns false
/// for a move only wrapped type.
bool isPureMoveOnly() const;

/// Return true if this is a value type (struct/enum) that requires
/// deinitialization beyond destruction of its members.
bool isValueTypeWithDeinit() const;
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ llvm::StringRef swift::getProtocolName(KnownProtocolKind kind) {
llvm_unreachable("bad KnownProtocolKind");
}

KnownProtocolSet swift::getInvertableProtocols() {
return { KnownProtocolKind::Copyable };
}

namespace {
enum class SearchPathKind : uint8_t {
Import = 1 << 0,
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3221,6 +3221,12 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr, void, StringRef>,
printFoot();
}

void visitInverseTypeRepr(InverseTypeRepr *T, StringRef label) {
printCommon("inverse", label);
printRec(T->getConstraint());
printFoot();
}

void visitArrayTypeRepr(ArrayTypeRepr *T, StringRef label) {
printCommon("type_array", label);
printRec(T->getBase());
Expand Down
9 changes: 7 additions & 2 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//===--- ASTPrinter.cpp - Swift Language AST Printer ----------------------===//
//
// This source file is part of the Swift.org open source project
//
Expand Down Expand Up @@ -3338,7 +3337,7 @@ static bool usesFeatureMoveOnly(Decl *decl) {
// Check for move-only types in the types of this declaration.
if (Type type = value->getInterfaceType()) {
bool hasMoveOnly = type.findIf([](Type type) {
return type->isPureMoveOnly();
return type->isNoncopyable();
});

if (hasMoveOnly)
Expand Down Expand Up @@ -3385,6 +3384,12 @@ static bool usesFeatureMoveOnlyPartialConsumption(Decl *decl) {
return false;
}

static bool usesFeatureNoncopyableGenerics(Decl *decl) {
// FIXME: need to look for suppressed entries on generic parameters or
// inheritance clauses!
return false;
}

static bool usesFeatureOneWayClosureParameters(Decl *decl) {
return false;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/ASTWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2210,6 +2210,10 @@ bool Traversal::visitExistentialTypeRepr(ExistentialTypeRepr *T) {
return doIt(T->getConstraint());
}

bool Traversal::visitInverseTypeRepr(InverseTypeRepr *T) {
return doIt(T->getConstraint());
}

bool Traversal::visitPlaceholderTypeRepr(PlaceholderTypeRepr *T) {
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7529,7 +7529,7 @@ LifetimeAnnotation ParamDecl::getLifetimeAnnotation() const {
auto specifier = getSpecifier();
// Copyable parameters which are consumed have eager-move semantics.
if (specifier == ParamDecl::Specifier::Consuming &&
!getTypeInContext()->isPureMoveOnly()) {
!getTypeInContext()->isNoncopyable()) {
if (getAttrs().hasAttribute<NoEagerMoveAttr>())
return LifetimeAnnotation::Lexical;
return LifetimeAnnotation::EagerMove;
Expand Down Expand Up @@ -9765,7 +9765,7 @@ LifetimeAnnotation FuncDecl::getLifetimeAnnotation() const {
// Copyable parameters which are consumed have eager-move semantics.
if (getSelfAccessKind() == SelfAccessKind::Consuming) {
auto *selfDecl = getImplicitSelfDecl();
if (selfDecl && !selfDecl->getTypeInContext()->isPureMoveOnly()) {
if (selfDecl && !selfDecl->getTypeInContext()->isNoncopyable()) {
if (getAttrs().hasAttribute<NoEagerMoveAttr>())
return LifetimeAnnotation::Lexical;
return LifetimeAnnotation::EagerMove;
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1797,7 +1797,7 @@ static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(

// Only metatypes of Copyable types are Copyable.
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable) &&
!metatypeType->getInstanceType()->isPureMoveOnly()) {
!metatypeType->getInstanceType()->isNoncopyable()) {
return ProtocolConformanceRef(
ctx.getBuiltinConformance(type, protocol,
BuiltinConformanceKind::Synthesized));
Expand Down
1 change: 1 addition & 0 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3018,6 +3018,7 @@ directReferencesForTypeRepr(Evaluator &evaluator,
case TypeReprKind::OpaqueReturn:
case TypeReprKind::NamedOpaqueReturn:
case TypeReprKind::Existential:
case TypeReprKind::Inverse:
return { };

case TypeReprKind::Fixed:
Expand Down
29 changes: 29 additions & 0 deletions lib/AST/RequirementMachine/RequirementLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@ void swift::rewriting::realizeInheritedRequirements(
auto inheritedTypes = decl->getInherited();
auto *dc = decl->getInnermostDeclContext();
auto *moduleForInference = dc->getParentModule();
auto defaults = getInvertableProtocols();

for (auto index : inheritedTypes.getIndices()) {
Type inheritedType =
Expand All @@ -749,13 +750,41 @@ void swift::rewriting::realizeInheritedRequirements(

auto *typeRepr = inheritedTypes.getTypeRepr(index);
SourceLoc loc = (typeRepr ? typeRepr->getStartLoc() : SourceLoc());

// For any inverses, we only need to cancel out a default requirement.
if (dyn_cast_or_null<InverseTypeRepr>(typeRepr)) {
if (auto protoTy = inheritedType->getAs<ProtocolType>())
if (auto protoDecl = protoTy->getDecl())
if (auto kp = protoDecl->getKnownProtocolKind())
defaults.remove(*kp);

continue;
}

if (shouldInferRequirements) {
inferRequirements(inheritedType, loc, moduleForInference,
decl->getInnermostDeclContext(), result);
}

realizeTypeRequirement(dc, type, inheritedType, loc, result, errors);
}

auto &ctx = dc->getASTContext();
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
// Add the remaining default conformance requirements to this
// associated type or generic type param.
for (auto kp : defaults) {
ProtocolDecl *decl = ctx.getProtocol(kp);
assert(decl && "couldn't load protocol??");

SourceLoc loc = decl->getLoc();
Type protocolType = decl->getDeclaredInterfaceType();

// Add the protocol as an "inferred" requirement.
Requirement req(RequirementKind::Conformance, type, protocolType);
result.push_back({req, loc, /*wasInferred=*/true});
}
}
}

/// StructuralRequirementsRequest realizes all the user-written requirements
Expand Down
6 changes: 3 additions & 3 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,18 +157,18 @@ bool TypeBase::isMarkerExistential() {
return true;
}

bool TypeBase::isPureMoveOnly() {
bool TypeBase::isNoncopyable() {
if (auto *nom = getAnyNominal())
return nom->isMoveOnly();

if (auto *expansion = getAs<PackExpansionType>()) {
return expansion->getPatternType()->isPureMoveOnly();
return expansion->getPatternType()->isNoncopyable();
}

// if any components of the tuple are move-only, then the tuple is move-only.
if (auto *tupl = getCanonicalType()->getAs<TupleType>()) {
for (auto eltTy : tupl->getElementTypes())
if (eltTy->isPureMoveOnly())
if (eltTy->isNoncopyable())
return true;
}

Expand Down
6 changes: 6 additions & 0 deletions lib/AST/TypeRepr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,12 @@ void NamedOpaqueReturnTypeRepr::printImpl(ASTPrinter &Printer,
printTypeRepr(Base, Printer, Opts);
}

void InverseTypeRepr::printImpl(ASTPrinter &Printer,
const PrintOptions &Opts) const {
Printer << "~";
printTypeRepr(Constraint, Printer, Opts);
}

void SpecifierTypeRepr::printImpl(ASTPrinter &Printer,
const PrintOptions &Opts) const {
switch (getKind()) {
Expand Down
4 changes: 2 additions & 2 deletions lib/IRGen/GenReflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ getTypeRefByFunction(IRGenModule &IGM,

// If a type is noncopyable, lie about the resolved type unless the
// runtime is sufficiently aware of noncopyable types.
if (substT->isPureMoveOnly()) {
if (substT->isNoncopyable()) {
// Darwin-based platforms have ABI stability, and we want binaries
// that use noncopyable types nongenerically today to be forward
// compatible with a future OS runtime that supports noncopyable
Expand Down Expand Up @@ -391,7 +391,7 @@ getTypeRefImpl(IRGenModule &IGM,
// noncopyable, use a function to emit the type ref which will look for a
// signal from future runtimes whether they support noncopyable types before
// exposing their metadata to them.
if (type->isPureMoveOnly()) {
if (type->isNoncopyable()) {
IGM.IRGen.noteUseOfTypeMetadata(type);
return getTypeRefByFunction(IGM, sig, type);
}
Expand Down
Loading