mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
287 lines
9.7 KiB
C++
287 lines
9.7 KiB
C++
//===--- Requirement.h - Swift Requirement ASTs -----------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the Requirement class and subclasses.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_AST_REQUIREMENT_H
|
|
#define SWIFT_AST_REQUIREMENT_H
|
|
|
|
#include "swift/AST/LayoutConstraint.h"
|
|
#include "swift/AST/RequirementKind.h"
|
|
#include "swift/AST/KnownProtocols.h"
|
|
#include "swift/AST/Type.h"
|
|
#include "swift/Basic/Debug.h"
|
|
#include "llvm/ADT/Hashing.h"
|
|
#include "llvm/ADT/PointerIntPair.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
namespace swift {
|
|
class GenericContext;
|
|
|
|
/// Return type of Requirement::checkRequirement().
|
|
enum class CheckRequirementResult : uint8_t {
|
|
/// The requirement was fully satisfied.
|
|
Success,
|
|
|
|
/// The subject type conforms conditionally; the sub-requirements are
|
|
/// conditional requirements which must be checked.
|
|
ConditionalConformance,
|
|
|
|
/// The subject type is a pack type; the sub-requirements are the
|
|
/// element-wise requirements which must be checked.
|
|
PackRequirement,
|
|
|
|
/// The requirement cannot ever be satisfied.
|
|
RequirementFailure,
|
|
|
|
/// Some other requirement is expected to fail, or there was an invalid
|
|
/// conformance and an error should be diagnosed elsewhere, so this
|
|
/// requirement does not need to be diagnosed.
|
|
SubstitutionFailure
|
|
};
|
|
|
|
/// A single requirement placed on the type parameters (or associated
|
|
/// types thereof) of a
|
|
class Requirement {
|
|
llvm::PointerIntPair<Type, 3, RequirementKind> FirstTypeAndKind;
|
|
/// The second element of the requirement. Its content is dependent
|
|
/// on the requirement kind.
|
|
/// The payload of the following enum should always match the kind!
|
|
/// Any access to the fields of this enum should first check if the
|
|
/// requested access matches the kind of the requirement.
|
|
union {
|
|
Type SecondType;
|
|
LayoutConstraint SecondLayout;
|
|
};
|
|
|
|
public:
|
|
/// Create a conformance or same-type requirement.
|
|
Requirement(RequirementKind kind, Type first, Type second)
|
|
: FirstTypeAndKind(first, kind), SecondType(second) {
|
|
assert(first);
|
|
assert(second);
|
|
assert(kind != RequirementKind::Layout);
|
|
}
|
|
|
|
/// Create a layout constraint requirement.
|
|
Requirement(RequirementKind kind, Type first, LayoutConstraint second)
|
|
: FirstTypeAndKind(first, kind), SecondLayout(second) {
|
|
assert(first);
|
|
assert(second);
|
|
assert(kind == RequirementKind::Layout);
|
|
}
|
|
|
|
|
|
/// Determine the kind of requirement.
|
|
RequirementKind getKind() const { return FirstTypeAndKind.getInt(); }
|
|
|
|
/// Retrieve the first type.
|
|
Type getFirstType() const {
|
|
return FirstTypeAndKind.getPointer();
|
|
}
|
|
|
|
/// Retrieve the second type.
|
|
Type getSecondType() const {
|
|
assert(getKind() != RequirementKind::Layout);
|
|
return SecondType;
|
|
}
|
|
|
|
/// Retrieve the layout constraint.
|
|
LayoutConstraint getLayoutConstraint() const {
|
|
assert(getKind() == RequirementKind::Layout);
|
|
return SecondLayout;
|
|
}
|
|
|
|
friend llvm::hash_code hash_value(const Requirement &requirement) {
|
|
using llvm::hash_value;
|
|
|
|
llvm::hash_code first =
|
|
hash_value(requirement.FirstTypeAndKind.getOpaqueValue());
|
|
llvm::hash_code second;
|
|
switch (requirement.getKind()) {
|
|
case RequirementKind::SameShape:
|
|
case RequirementKind::Conformance:
|
|
case RequirementKind::Superclass:
|
|
case RequirementKind::SameType:
|
|
second = hash_value(requirement.getSecondType());
|
|
break;
|
|
|
|
case RequirementKind::Layout:
|
|
second = hash_value(requirement.getLayoutConstraint());
|
|
break;
|
|
}
|
|
|
|
return llvm::hash_combine(first, second);
|
|
}
|
|
|
|
friend bool operator==(const Requirement &lhs,
|
|
const Requirement &rhs) {
|
|
if (lhs.FirstTypeAndKind.getOpaqueValue()
|
|
!= rhs.FirstTypeAndKind.getOpaqueValue())
|
|
return false;
|
|
|
|
switch (lhs.getKind()) {
|
|
case RequirementKind::SameShape:
|
|
case RequirementKind::Conformance:
|
|
case RequirementKind::Superclass:
|
|
case RequirementKind::SameType:
|
|
return lhs.getSecondType().getPointer() ==
|
|
rhs.getSecondType().getPointer();
|
|
|
|
case RequirementKind::Layout:
|
|
return lhs.getLayoutConstraint() == rhs.getLayoutConstraint();
|
|
}
|
|
llvm_unreachable("Unhandled RequirementKind in switch");
|
|
}
|
|
|
|
friend bool operator!=(const Requirement &lhs,
|
|
const Requirement &rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
/// Whether this requirement's types contain ErrorTypes.
|
|
bool hasError() const;
|
|
|
|
/// Whether this requirement is written with canonical types.
|
|
bool isCanonical() const;
|
|
|
|
/// Canonicalize the types in this requirement.
|
|
Requirement getCanonical() const;
|
|
|
|
/// Subst the types involved in this requirement.
|
|
///
|
|
/// The \c args arguments are passed through to Type::subst.
|
|
template <typename ...Args>
|
|
Requirement subst(Args &&...args) const {
|
|
auto newFirst = getFirstType().subst(std::forward<Args>(args)...);
|
|
switch (getKind()) {
|
|
case RequirementKind::SameShape:
|
|
case RequirementKind::Conformance:
|
|
case RequirementKind::Superclass:
|
|
case RequirementKind::SameType: {
|
|
auto newSecond = getSecondType().subst(std::forward<Args>(args)...);
|
|
return Requirement(getKind(), newFirst, newSecond);
|
|
}
|
|
case RequirementKind::Layout:
|
|
return Requirement(getKind(), newFirst, getLayoutConstraint());
|
|
}
|
|
|
|
llvm_unreachable("Unhandled RequirementKind in switch.");
|
|
}
|
|
|
|
ProtocolDecl *getProtocolDecl() const;
|
|
|
|
/// Determines if this substituted requirement is satisfied.
|
|
///
|
|
/// \param subReqs An out parameter initialized to a list of simpler
|
|
/// requirements which the caller must check to ensure this
|
|
/// requirement is completely satisfied.
|
|
/// \param isolatedConformances If non-NULL, will be provided with all of the
|
|
/// isolated conformances that
|
|
CheckRequirementResult checkRequirement(
|
|
SmallVectorImpl<Requirement> &subReqs,
|
|
bool allowMissing = false,
|
|
SmallVectorImpl<ProtocolConformance *> *isolatedConformances = nullptr
|
|
) const;
|
|
|
|
/// Determines if this substituted requirement can ever be satisfied,
|
|
/// possibly with additional substitutions.
|
|
///
|
|
/// For example, if 'T' is unconstrained, then a superclass requirement
|
|
/// 'T : C' can be satisfied; however, if 'T' already has an unrelated
|
|
/// superclass requirement, 'T : C' cannot be satisfied.
|
|
bool canBeSatisfied() const;
|
|
|
|
/// True if the requirement states a conformance to an invertible protocol
|
|
/// that is implied by default (such as `Copyable` or `Escapable`.
|
|
bool isInvertibleProtocolRequirement() const;
|
|
|
|
/// Linear order on requirements in a generic signature.
|
|
int compare(const Requirement &other) const;
|
|
|
|
SWIFT_DEBUG_DUMP;
|
|
void dump(raw_ostream &out) const;
|
|
void print(raw_ostream &os, const PrintOptions &opts) const;
|
|
void print(ASTPrinter &printer, const PrintOptions &opts) const;
|
|
};
|
|
|
|
inline void simple_display(llvm::raw_ostream &out, const Requirement &req) {
|
|
req.print(out, PrintOptions());
|
|
}
|
|
|
|
enum class CheckRequirementsResult : uint8_t {
|
|
Success,
|
|
|
|
/// One of the requirements was unsatisfied.
|
|
RequirementFailure,
|
|
|
|
/// One of the requirements contained error types, either because of an
|
|
/// invalid conformance or because it contained a member type that was
|
|
/// dependent on an earlier conformance requirement that failed.
|
|
SubstitutionFailure
|
|
};
|
|
|
|
/// Check if each substituted requirement is satisfied. The requirement must
|
|
/// not contain any type parameters.
|
|
CheckRequirementsResult checkRequirements(ArrayRef<Requirement> requirements);
|
|
|
|
/// Check if each substituted requirement is satisfied. If the requirement
|
|
/// contains type parameters, and the answer would depend on the context of
|
|
/// those type parameters, then `nullopt` is returned.
|
|
std::optional<CheckRequirementsResult>
|
|
checkRequirementsWithoutContext(ArrayRef<Requirement> requirements);
|
|
|
|
/// Check if each requirement is satisfied after applying the given
|
|
/// substitutions. The substitutions must replace all type parameters that
|
|
/// appear in the requirement with concrete types or archetypes.
|
|
CheckRequirementsResult checkRequirements(ArrayRef<Requirement> requirements,
|
|
TypeSubstitutionFn substitutions,
|
|
SubstOptions options = std::nullopt);
|
|
|
|
/// A requirement as written in source, together with a source location. See
|
|
/// ProtocolDecl::getStructuralRequirements().
|
|
struct StructuralRequirement {
|
|
/// A requirement with resolved in the structural resolution stage.
|
|
Requirement req;
|
|
|
|
/// The source location where the requirement is written, for diagnostics.
|
|
SourceLoc loc;
|
|
};
|
|
|
|
/// An "anti-conformance" requirement `Subject: ~Protocol`.
|
|
struct InverseRequirement {
|
|
Type subject;
|
|
ProtocolDecl *protocol;
|
|
SourceLoc loc;
|
|
|
|
InverseRequirement(Type subject, ProtocolDecl *protocol, SourceLoc loc);
|
|
|
|
InvertibleProtocolKind getKind() const;
|
|
|
|
/// Linear order on inverse requirements in a generic signature.
|
|
int compare(const InverseRequirement &other) const;
|
|
|
|
/// Appends additional requirements corresponding to defaults for the given
|
|
/// generic parameters.
|
|
static void expandDefaults(ASTContext &ctx,
|
|
ArrayRef<Type> gps,
|
|
SmallVectorImpl<StructuralRequirement> &result);
|
|
|
|
void print(raw_ostream &os, const PrintOptions &opts, bool forInherited=false) const;
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|