Skip to content

RequirementMachine: A term rewriting system for reasoning about generic signatures #37675

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 20 commits into from
Jun 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b36f733
GSB: Fix a FrontendStatsTracer
slavapestov May 29, 2021
0974ad9
AST: Remove some dead code from LayoutConstraint.h
slavapestov Jun 1, 2021
6008e6a
RequirementMachine: Initial skeleton implementation
slavapestov May 27, 2021
69b7a64
RequirementMachine: Split off RewriteSystemBuilder
slavapestov May 28, 2021
793474f
RequirementMachine: Associated type inheritance
slavapestov May 28, 2021
f69b883
RequirementMachine: Topological order for protocol declarations
slavapestov May 28, 2021
efae2bf
RequirementMachine: Completion depth limit
slavapestov May 29, 2021
863f63a
RequirementMachine: Fixes to get stdlib to build
slavapestov May 29, 2021
69f4d07
RequirementMachine: Fix a FrontendStatsTracer
slavapestov May 29, 2021
bc5e26b
RequirementMachine: Lower limit
slavapestov May 29, 2021
8aaea2b
RequirementMachine: Preliminary support for layout requirements
slavapestov Jun 1, 2021
ff157e6
RequirementMachine: Add notion of 'merged' associated type atoms
slavapestov Jun 1, 2021
85d17a6
RequirementMachine: Split off ProtocolGraph into its own file
slavapestov Jun 1, 2021
194eb29
RequirementMachine: Move the protocol graph into the rewrite system
slavapestov Jun 1, 2021
91ab25d
RequirementMachine: Update completion worklist inside addRule()
slavapestov Jun 2, 2021
44eb0cf
RequirementMachine: Experiment with merging associated types
slavapestov Jun 2, 2021
20d5d77
RequirementMachine: Add flags for completion depth and step limits
slavapestov Jun 2, 2021
c408271
RequirementMachine: Write a bunch of comments
slavapestov Jun 2, 2021
6df75ee
RequirementMachine: Remove bogus assertion
slavapestov Jun 2, 2021
a7486b4
RequirementMachine: Code review feedback from @CodaFi
slavapestov Jun 2, 2021
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
6 changes: 6 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ namespace swift {
class TupleTypeElt;
class EnumElementDecl;
class ProtocolDecl;
class RequirementMachine;
class SubstitutableType;
class SourceManager;
class ValueDecl;
Expand Down Expand Up @@ -1132,6 +1133,11 @@ class ASTContext final {
GenericSignatureBuilder *getOrCreateGenericSignatureBuilder(
CanGenericSignature sig);

/// Retrieve or create a term rewriting system for answering queries on
/// type parameters written against the given generic signature.
RequirementMachine *getOrCreateRequirementMachine(
CanGenericSignature sig);

/// Retrieve a generic signature with a single unconstrained type parameter,
/// like `<T>`.
CanGenericSignature getSingleGenericParameterSignature() const;
Expand Down
16 changes: 4 additions & 12 deletions include/swift/AST/LayoutConstraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,10 @@ class LayoutConstraint {
bool operator!=(LayoutConstraint rhs) const {
return !(*this == rhs);
}

/// Defines a somewhat arbitrary linear order on layout constraints.
/// -1 if this < rhs, 0 if this == rhs, 1 if this > rhs.
int compare(LayoutConstraint rhs) const;
};

// Permit direct uses of isa/cast/dyn_cast on LayoutConstraint.
Expand Down Expand Up @@ -313,12 +317,6 @@ struct LayoutConstraintLoc {

bool isError() const;

// FIXME: We generally shouldn't need to build LayoutConstraintLoc without
// a location.
static LayoutConstraintLoc withoutLoc(LayoutConstraint Layout) {
return LayoutConstraintLoc(Layout, SourceLoc());
}

/// Get the representative location of this type, for diagnostic
/// purposes.
SourceLoc getLoc() const { return Loc; }
Expand All @@ -328,13 +326,7 @@ struct LayoutConstraintLoc {
bool hasLocation() const { return Loc.isValid(); }
LayoutConstraint getLayoutConstraint() const { return Layout; }

void setLayoutConstraint(LayoutConstraint value) {
Layout = value;
}

bool isNull() const { return Layout.isNull(); }

LayoutConstraintLoc clone(ASTContext &ctx) const { return *this; }
};

/// Checks if ID is a name of a layout constraint and returns this
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/LayoutConstraintKind.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/DataTypes.h"

#ifndef SWIFT_LAYOUT_CONSTRAINTKIND_H
#define SWIFT_LAYOUT_CONSTRAINTKIND_H

Expand Down
113 changes: 113 additions & 0 deletions include/swift/AST/ProtocolGraph.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//===--- ProtocolGraph.h - Collects information about protocols -*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_PROTOCOLGRAPH_H
#define SWIFT_PROTOCOLGRAPH_H

#include "swift/AST/Requirement.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/TinyPtrVector.h"

namespace swift {

class ProtocolDecl;
class AssociatedTypeDecl;

namespace rewriting {

/// Stores cached information about a protocol.
struct ProtocolInfo {
/// All immediately-inherited protocols.
ArrayRef<ProtocolDecl *> Inherited;

/// Transitive closure of inherited protocols; does not include the protocol
/// itself. Computed by ProtocolGraph::computeInheritedProtocols().
llvm::TinyPtrVector<const ProtocolDecl *> AllInherited;

/// Transitive closure of inherited associated types together with all
/// associated types from the protocol itself. Computed by
/// ProtocolGraph::computeInheritedAssociatedTypes().
llvm::TinyPtrVector<AssociatedTypeDecl *> AssociatedTypes;

/// The protocol's requirement signature.
ArrayRef<Requirement> Requirements;

/// Used by ProtocolGraph::computeProtocolDepth() to detect circularity.
unsigned Mark : 1;

/// Longest chain of protocol refinements, including this one. Greater than
/// zero on valid code, might be zero if there's a cycle. Computed by
/// ProtocolGraph::computeLinearOrder().
unsigned Depth : 31;

/// Index of the protocol in the linear order. Computed by
/// ProtocolGraph::computeLinearOrder().
unsigned Index : 32;

ProtocolInfo() {
Mark = 0;
Depth = 0;
Index = 0;
}

ProtocolInfo(ArrayRef<ProtocolDecl *> inherited,
llvm::TinyPtrVector<AssociatedTypeDecl *> &&types,
ArrayRef<Requirement> reqs)
: Inherited(inherited),
AssociatedTypes(types),
Requirements(reqs) {
Mark = 0;
Depth = 0;
Index = 0;
}
};

/// Stores cached information about all protocols transtively
/// referenced from a set of generic requirements.
///
/// Out-of-line methods are documented in ProtocolGraph.cpp.
struct ProtocolGraph {
llvm::DenseMap<const ProtocolDecl *, ProtocolInfo> Info;
std::vector<const ProtocolDecl *> Protocols;
bool Debug = false;

void visitRequirements(ArrayRef<Requirement> reqs);

const ProtocolInfo &getProtocolInfo(
const ProtocolDecl *proto) const;

void addProtocol(const ProtocolDecl *proto);

void computeTransitiveClosure();

void computeLinearOrder();

void computeInheritedAssociatedTypes();

void computeInheritedProtocols();

int compareProtocols(const ProtocolDecl *lhs,
const ProtocolDecl *rhs) const;

bool inheritsFrom(const ProtocolDecl *thisProto,
const ProtocolDecl *otherProto) const;

private:
unsigned computeProtocolDepth(const ProtocolDecl *proto);
};

} // end namespace rewriting

} // end namespace swift

#endif
62 changes: 62 additions & 0 deletions include/swift/AST/RequirementMachine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===--- RequirementMachine.h - Generics with term rewriting ----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_REQUIREMENTMACHINE_H
#define SWIFT_REQUIREMENTMACHINE_H

namespace swift {

class ASTContext;
class AssociatedTypeDecl;
class CanGenericSignature;
class CanType;
class GenericSignature;
class ProtocolDecl;
class Requirement;

namespace rewriting {

class Term;

Term getTermForType(CanType paramType, const ProtocolDecl *proto);

} // end namespace rewriting

/// Wraps a rewrite system with higher-level operations in terms of
/// generic signatures and interface types.
class RequirementMachine final {
friend class ASTContext;

struct Implementation;

ASTContext &Context;
Implementation *Impl;

explicit RequirementMachine(ASTContext &ctx);

RequirementMachine(const RequirementMachine &) = delete;
RequirementMachine(RequirementMachine &&) = delete;
RequirementMachine &operator=(const RequirementMachine &) = delete;
RequirementMachine &operator=(RequirementMachine &&) = delete;

void addGenericSignature(CanGenericSignature sig);

bool isComplete() const;
void markComplete();

public:
~RequirementMachine();
};

} // end namespace swift

#endif
Loading