Skip to content

[GSB] Basic infrastructure for delaying and reprocessing requirements #8707

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
Apr 12, 2017
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
162 changes: 119 additions & 43 deletions include/swift/AST/GenericSignatureBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class GenericSignatureBuilder {

class FloatingRequirementSource;

class DelayedRequirement;

/// Describes a specific constraint on a potential archetype.
template<typename T>
struct Constraint {
Expand Down Expand Up @@ -178,6 +180,35 @@ class GenericSignatureBuilder {

friend class RequirementSource;

/// The result of introducing a new constraint.
enum class ConstraintResult {
/// The constraint was resolved and the relative potential archetypes
/// have been updated.
Resolved,

/// The constraint was written directly on a concrete type.
Concrete,

/// The constraint conflicted with existing constraints in some way;
/// the generic signature is ill-formed.
Conflicting,

/// The constraint could not be resolved immediately.
Unresolved,
};

/// Enum used to indicate how we should handle a constraint that cannot be
/// processed immediately for some reason.
enum class UnresolvedHandlingKind : char {
/// Generate a new, unresolved constraint and consider the constraint
/// "resolved" at this point.
GenerateConstraints = 0,

/// Do not generate a new constraint; rather, return
/// \c ConstraintResult::Unresolved and let the caller handle it.
ReturnUnresolved = 1,
};

private:
class InferRequirementsWalker;
friend class InferRequirementsWalker;
Expand All @@ -193,13 +224,15 @@ class GenericSignatureBuilder {

/// When a particular requirement cannot be resolved due to, e.g., a
/// currently-unresolvable or nested type, this routine should be
/// called to record the unresolved requirement to be reconsidered later.
/// called to cope with the unresolved requirement.
///
/// \returns false, which is used elsewhere to indicate "no failure".
bool recordUnresolvedRequirement(RequirementKind kind,
/// \returns \c ConstraintResult::Resolved or ConstraintResult::Delayed,
/// as appropriate based on \c unresolvedHandling.
ConstraintResult handleUnresolvedRequirement(RequirementKind kind,
UnresolvedType lhs,
RequirementRHS rhs,
FloatingRequirementSource source);
FloatingRequirementSource source,
UnresolvedHandlingKind unresolvedHandling);

/// Retrieve the constraint source conformance for the superclass constraint
/// of the given potential archetype (if present) to the given protocol.
Expand All @@ -214,14 +247,15 @@ class GenericSignatureBuilder {

/// \brief Add a new conformance requirement specifying that the given
/// potential archetype conforms to the given protocol.
bool addConformanceRequirement(PotentialArchetype *T,
ProtocolDecl *Proto,
const RequirementSource *Source);
ConstraintResult addConformanceRequirement(PotentialArchetype *T,
ProtocolDecl *Proto,
const RequirementSource *Source);

bool addConformanceRequirement(PotentialArchetype *T,
ProtocolDecl *Proto,
const RequirementSource *Source,
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
ConstraintResult addConformanceRequirement(
PotentialArchetype *T,
ProtocolDecl *Proto,
const RequirementSource *Source,
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);

public:
/// \brief Add a new same-type requirement between two fully resolved types
Expand All @@ -231,7 +265,7 @@ class GenericSignatureBuilder {
/// incompatible (e.g. \c Foo<Bar<T>> and \c Foo<Baz>), \c diagnoseMismatch is
/// called with the two types that don't match (\c Bar<T> and \c Baz for the
/// previous example).
bool
ConstraintResult
addSameTypeRequirementDirect(
ResolvedType paOrT1, ResolvedType paOrT2,
FloatingRequirementSource Source,
Expand All @@ -241,57 +275,67 @@ class GenericSignatureBuilder {
/// (output of GenericSignatureBuilder::resolve).
///
/// The two types must not be incompatible concrete types.
bool addSameTypeRequirementDirect(ResolvedType paOrT1, ResolvedType paOrT2,
FloatingRequirementSource Source);
ConstraintResult addSameTypeRequirementDirect(
ResolvedType paOrT1,
ResolvedType paOrT2,
FloatingRequirementSource Source);

/// \brief Add a new same-type requirement between two unresolved types.
///
/// The types are resolved with \c GenericSignatureBuilder::resolve, and must
/// not be incompatible concrete types.
bool addSameTypeRequirement(UnresolvedType paOrT1, UnresolvedType paOrT2,
FloatingRequirementSource Source);
ConstraintResult addSameTypeRequirement(
UnresolvedType paOrT1,
UnresolvedType paOrT2,
FloatingRequirementSource Source,
UnresolvedHandlingKind unresolvedHandling);

/// \brief Add a new same-type requirement between two unresolved types.
///
/// The types are resolved with \c GenericSignatureBuilder::resolve. \c
/// diagnoseMismatch is called if the two types refer to incompatible concrete
/// types.
bool
ConstraintResult
addSameTypeRequirement(UnresolvedType paOrT1, UnresolvedType paOrT2,
FloatingRequirementSource Source,
UnresolvedHandlingKind unresolvedHandling,
llvm::function_ref<void(Type, Type)> diagnoseMismatch);

/// Update the superclass for the equivalence class of \c T.
///
/// This assumes that the constraint has already been recorded
bool updateSuperclass(PotentialArchetype *T,
/// This assumes that the constraint has already been recorded.
void updateSuperclass(PotentialArchetype *T,
Type superclass,
const RequirementSource *source);

private:
/// \brief Add a new superclass requirement specifying that the given
/// potential archetype has the given type as an ancestor.
bool addSuperclassRequirementDirect(PotentialArchetype *T,
Type Superclass,
const RequirementSource *Source);
ConstraintResult addSuperclassRequirementDirect(
PotentialArchetype *T,
Type Superclass,
const RequirementSource *Source);

/// \brief Add a new type requirement specifying that the given
/// type conforms-to or is a superclass of the second type.
bool addTypeRequirement(UnresolvedType subject,
ConstraintResult addTypeRequirement(
UnresolvedType subject,
UnresolvedType constraint,
FloatingRequirementSource source,
UnresolvedHandlingKind unresolvedHandling,
llvm::SmallPtrSetImpl<ProtocolDecl *> *visited
= nullptr);

/// \brief Add a new conformance requirement specifying that the given
/// potential archetypes are equivalent.
bool addSameTypeRequirementBetweenArchetypes(PotentialArchetype *T1,
ConstraintResult addSameTypeRequirementBetweenArchetypes(
PotentialArchetype *T1,
PotentialArchetype *T2,
const RequirementSource *Source);

/// \brief Add a new conformance requirement specifying that the given
/// potential archetype is bound to a concrete type.
bool addSameTypeRequirementToConcrete(PotentialArchetype *T,
ConstraintResult addSameTypeRequirementToConcrete(PotentialArchetype *T,
Type Concrete,
const RequirementSource *Source);

Expand All @@ -300,26 +344,30 @@ class GenericSignatureBuilder {
///
/// \param diagnoseMismatch Callback invoked when the types in the same-type
/// requirement mismatch.
bool addSameTypeRequirementBetweenConcrete(
ConstraintResult addSameTypeRequirementBetweenConcrete(
Type T1, Type T2, FloatingRequirementSource Source,
llvm::function_ref<void(Type, Type)> diagnoseMismatch);

/// \brief Add a new layout requirement directly on the potential archetype.
///
/// \returns true if this requirement makes the set of requirements
/// inconsistent, in which case a diagnostic will have been issued.
bool addLayoutRequirementDirect(PotentialArchetype *PAT,
LayoutConstraint Layout,
const RequirementSource *Source);
ConstraintResult addLayoutRequirementDirect(PotentialArchetype *PAT,
LayoutConstraint Layout,
const RequirementSource *Source);

/// Add a new layout requirement to the subject.
bool addLayoutRequirement(UnresolvedType subject,
LayoutConstraint layout,
FloatingRequirementSource source);
ConstraintResult addLayoutRequirement(
UnresolvedType subject,
LayoutConstraint layout,
FloatingRequirementSource source,
UnresolvedHandlingKind unresolvedHandling);

/// Add the requirements placed on the given type parameter
/// to the given potential archetype.
bool addInheritedRequirements(TypeDecl *decl, PotentialArchetype *pa,
ConstraintResult addInheritedRequirements(
TypeDecl *decl,
PotentialArchetype *pa,
const RequirementSource *parentSource,
llvm::SmallPtrSetImpl<ProtocolDecl *> &visited);

Expand Down Expand Up @@ -379,15 +427,15 @@ class GenericSignatureBuilder {
///
/// \returns true if this requirement makes the set of requirements
/// inconsistent, in which case a diagnostic will have been issued.
bool addRequirement(const RequirementRepr *req);
ConstraintResult addRequirement(const RequirementRepr *req);

/// \brief Add a new requirement.
///
/// \returns true if this requirement makes the set of requirements
/// inconsistent, in which case a diagnostic will have been issued.
bool addRequirement(const RequirementRepr *Req,
FloatingRequirementSource source,
const SubstitutionMap *subMap);
ConstraintResult addRequirement(const RequirementRepr *Req,
FloatingRequirementSource source,
const SubstitutionMap *subMap);

/// \brief Add an already-checked requirement.
///
Expand All @@ -396,12 +444,15 @@ class GenericSignatureBuilder {
///
/// \returns true if this requirement makes the set of requirements
/// inconsistent, in which case a diagnostic will have been issued.
bool addRequirement(const Requirement &req, FloatingRequirementSource source,
const SubstitutionMap *subMap = nullptr);

bool addRequirement(const Requirement &req, FloatingRequirementSource source,
const SubstitutionMap *subMap,
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
ConstraintResult addRequirement(const Requirement &req,
FloatingRequirementSource source,
const SubstitutionMap *subMap = nullptr);

ConstraintResult addRequirement(
const Requirement &req,
FloatingRequirementSource source,
const SubstitutionMap *subMap,
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);

/// \brief Add all of a generic signature's parameters and requirements.
void addGenericSignature(GenericSignature *sig);
Expand Down Expand Up @@ -454,6 +505,9 @@ class GenericSignatureBuilder {
ArrayRef<GenericTypeParamType *> genericParams);

private:
/// Process any delayed requirements that can be handled now.
void processDelayedRequirements();

/// Describes the relationship between a given constraint and
/// the canonical constraint of the equivalence class.
enum class ConstraintRelation {
Expand Down Expand Up @@ -1519,6 +1573,28 @@ class GenericSignatureBuilder::PotentialArchetype {
friend class GenericSignatureBuilder;
};

/// Describes a requirement whose processing has been delayed for some reason.
class GenericSignatureBuilder::DelayedRequirement {
public:
RequirementKind kind;
UnresolvedType lhs;
RequirementRHS rhs;
FloatingRequirementSource source;
};

/// Whether the given constraint result signals an error.
inline bool isErrorResult(GenericSignatureBuilder::ConstraintResult result) {
switch (result) {
case GenericSignatureBuilder::ConstraintResult::Concrete:
case GenericSignatureBuilder::ConstraintResult::Conflicting:
return true;

case GenericSignatureBuilder::ConstraintResult::Resolved:
case GenericSignatureBuilder::ConstraintResult::Unresolved:
return false;
}
}

} // end namespace swift

#endif
45 changes: 43 additions & 2 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1277,9 +1277,50 @@ GenericSignatureBuilder *ASTContext::getOrCreateGenericSignatureBuilder(
llvm::errs() << "Original generic signature : ";
sig->print(llvm::errs());
llvm::errs() << "\nReprocessed generic signature: ";
builder->getGenericSignature()->getCanonicalSignature()
->print(llvm::errs());
auto reprocessedSig =
builder->getGenericSignature()->getCanonicalSignature();

reprocessedSig->print(llvm::errs());
llvm::errs() << "\n";

if (sig->getGenericParams().size() ==
reprocessedSig->getGenericParams().size() &&
sig->getRequirements().size() ==
reprocessedSig->getRequirements().size()) {
for (unsigned i : indices(sig->getRequirements())) {
auto sigReq = sig->getRequirements()[i];
auto reprocessedReq = reprocessedSig->getRequirements()[i];
if (sigReq.getKind() != reprocessedReq.getKind()) {
llvm::errs() << "Requirement mismatch:\n";
llvm::errs() << " Original: ";
sigReq.print(llvm::errs(), PrintOptions());
llvm::errs() << "\n Reprocessed: ";
reprocessedReq.print(llvm::errs(), PrintOptions());
llvm::errs() << "\n";
break;
}

if (!sigReq.getFirstType()->isEqual(reprocessedReq.getFirstType())) {
llvm::errs() << "First type mismatch, original is:\n";
sigReq.getFirstType().dump(llvm::errs());
llvm::errs() << "Reprocessed:\n";
reprocessedReq.getFirstType().dump(llvm::errs());
llvm::errs() << "\n";
break;
}

if (sigReq.getKind() == RequirementKind::SameType &&
!sigReq.getSecondType()->isEqual(reprocessedReq.getSecondType())) {
llvm::errs() << "Second type mismatch, original is:\n";
sigReq.getSecondType().dump(llvm::errs());
llvm::errs() << "Reprocessed:\n";
reprocessedReq.getSecondType().dump(llvm::errs());
llvm::errs() << "\n";
break;
}
}
}

llvm_unreachable("idempotency problem with a generic signature");
}
#endif
Expand Down
Loading