blob: 375dd9dd8d3a3b2771a2e8dbdd5a22933b4a7de4 [file] [log] [blame]
//===--- ConstraintSystem.h - Constraint-based Type Checking ----*- 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 provides the constraint-based type checker, anchored by the
// \c ConstraintSystem class, which provides type checking and type
// inference for expressions.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SEMA_PROTOCOL_H
#define SWIFT_SEMA_PROTOCOL_H
#include "swift/AST/RequirementEnvironment.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/AST/Witness.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
namespace swift {
class AccessScope;
class AssociatedTypeDecl;
class AvailabilityContext;
class DeclContext;
class NormalProtocolConformance;
class ProtocolDecl;
class TypeChecker;
class TypeRepr;
class ValueDecl;
/// A conflict between two inferred type witnesses for the same
/// associated type.
struct TypeWitnessConflict {
/// The associated type.
AssociatedTypeDecl *AssocType;
/// The first type.
Type FirstType;
/// The requirement to which the first witness was matched.
ValueDecl *FirstRequirement;
/// The witness from which the first type witness was inferred.
ValueDecl *FirstWitness;
/// The second type.
Type SecondType;
/// The requirement to which the second witness was matched.
ValueDecl *SecondRequirement;
/// The witness from which the second type witness was inferred.
ValueDecl *SecondWitness;
};
/// Describes the result of checking a type witness.
///
/// This class evaluates true if an error occurred.
class CheckTypeWitnessResult {
Type Requirement;
public:
CheckTypeWitnessResult() { }
CheckTypeWitnessResult(Type reqt) : Requirement(reqt) {}
Type getRequirement() const { return Requirement; }
bool isConformanceRequirement() const {
return Requirement->isExistentialType();
}
explicit operator bool() const { return !Requirement.isNull(); }
};
/// Check whether the given type witness can be used for the given
/// associated type.
///
/// \returns an empty result on success, or a description of the error.
CheckTypeWitnessResult checkTypeWitness(TypeChecker &tc, DeclContext *dc,
ProtocolDecl *proto,
AssociatedTypeDecl *assocType,
Type type);
/// The set of associated types that have been inferred by matching
/// the given value witness to its corresponding requirement.
struct InferredAssociatedTypesByWitness {
/// The witness we matched.
ValueDecl *Witness = nullptr;
/// The associated types inferred from matching this witness.
SmallVector<std::pair<AssociatedTypeDecl *, Type>, 4> Inferred;
/// Inferred associated types that don't meet the associated type
/// requirements.
SmallVector<std::tuple<AssociatedTypeDecl *, Type, CheckTypeWitnessResult>,
2> NonViable;
void dump(llvm::raw_ostream &out, unsigned indent) const;
LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
"only for use in the debugger");
};
/// The set of witnesses that were considered when attempting to
/// infer associated types.
typedef SmallVector<InferredAssociatedTypesByWitness, 2>
InferredAssociatedTypesByWitnesses;
/// A mapping from requirements to the set of matches with witnesses.
typedef SmallVector<std::pair<ValueDecl *,
InferredAssociatedTypesByWitnesses>, 4>
InferredAssociatedTypes;
/// A potential solution to the set of inferred type witnesses.
struct InferredTypeWitnessesSolution {
/// The set of type witnesses inferred by this solution, along
/// with the index into the value witnesses where the type was
/// inferred.
llvm::SmallDenseMap<AssociatedTypeDecl *, std::pair<Type, unsigned>, 4>
TypeWitnesses;
/// The value witnesses selected by this step of the solution.
SmallVector<std::pair<ValueDecl *, ValueDecl *>, 4> ValueWitnesses;
/// The number of value witnesses that occur in protocol
/// extensions.
unsigned NumValueWitnessesInProtocolExtensions;
#ifndef NDEBUG
LLVM_ATTRIBUTE_USED
#endif
void dump() const;
};
class RequirementEnvironment;
/// \brief The result of matching a particular declaration to a given
/// requirement.
enum class MatchKind : unsigned char {
/// \brief The witness matched the requirement exactly.
ExactMatch,
/// \brief There is a difference in optionality.
OptionalityConflict,
/// \brief The witness matched the requirement with some renaming.
RenamedMatch,
/// \brief The witness is invalid or has an invalid type.
WitnessInvalid,
/// \brief The kind of the witness and requirement differ, e.g., one
/// is a function and the other is a variable.
KindConflict,
/// \brief The types conflict.
TypeConflict,
/// The witness throws, but the requirement does not.
ThrowsConflict,
/// \brief The witness did not match due to static/non-static differences.
StaticNonStaticConflict,
/// \brief The witness is not settable, but the requirement is.
SettableConflict,
/// \brief The witness did not match due to prefix/non-prefix differences.
PrefixNonPrefixConflict,
/// \brief The witness did not match due to postfix/non-postfix differences.
PostfixNonPostfixConflict,
/// \brief The witness did not match because of mutating conflicts.
MutatingConflict,
/// \brief The witness did not match because of nonmutating conflicts.
NonMutatingConflict,
/// \brief The witness did not match because of __consuming conflicts.
ConsumingConflict,
/// The witness is not rethrows, but the requirement is.
RethrowsConflict,
/// The witness is explicitly @nonobjc but the requirement is @objc.
NonObjC,
};
/// Describes the kind of optional adjustment performed when
/// comparing two types.
enum class OptionalAdjustmentKind {
// No adjustment required.
None,
/// The witness can produce a 'nil' that won't be handled by
/// callers of the requirement. This is a type-safety problem.
ProducesUnhandledNil,
/// Callers of the requirement can provide 'nil', but the witness
/// does not handle it. This is a type-safety problem.
ConsumesUnhandledNil,
/// The witness handles 'nil', but won't ever be given a 'nil'.
/// This is not a type-safety problem.
WillNeverConsumeNil,
/// Callers of the requirement can expect to receive 'nil', but
/// the witness will never produce one. This is not a type-safety
/// problem.
WillNeverProduceNil,
/// The witness has an IUO that can be removed, because the
/// protocol doesn't need it. This is not a type-safety problem.
RemoveIUO,
/// The witness has an IUO that should be translated into a true
/// optional. This is not a type-safety problem.
IUOToOptional,
};
/// Once a witness has been found, there are several reasons it may
/// not be usable.
enum class CheckKind : unsigned {
/// The witness is OK.
Success,
/// The witness is less accessible than the requirement.
Access,
/// The witness is storage whose setter is less accessible than the
/// requirement.
AccessOfSetter,
/// The witness is less available than the requirement.
Availability,
/// The requirement was marked explicitly unavailable.
Unavailable,
/// The witness requires optional adjustments.
OptionalityConflict,
/// The witness is a constructor which is more failable than the
/// requirement.
ConstructorFailability,
/// The witness itself is inaccessible.
WitnessUnavailable,
};
/// Describes an optional adjustment made to a witness.
class OptionalAdjustment {
/// The kind of adjustment.
unsigned Kind : 16;
/// Whether this is a parameter adjustment (with an index) vs. a
/// result or value type adjustment (no index needed).
unsigned IsParameterAdjustment : 1;
/// The adjustment index, for parameter adjustments.
unsigned ParameterAdjustmentIndex : 15;
public:
/// Create a non-parameter optional adjustment.
explicit OptionalAdjustment(OptionalAdjustmentKind kind)
: Kind(static_cast<unsigned>(kind)), IsParameterAdjustment(false),
ParameterAdjustmentIndex(0) { }
/// Create an optional adjustment to a parameter.
OptionalAdjustment(OptionalAdjustmentKind kind,
unsigned parameterIndex)
: Kind(static_cast<unsigned>(kind)), IsParameterAdjustment(true),
ParameterAdjustmentIndex(parameterIndex) { }
/// Determine the kind of optional adjustment.
OptionalAdjustmentKind getKind() const {
return static_cast<OptionalAdjustmentKind>(Kind);
}
/// Determine whether this is a parameter adjustment.
bool isParameterAdjustment() const {
return IsParameterAdjustment;
}
/// Return the index of a parameter adjustment.
unsigned getParameterIndex() const {
assert(isParameterAdjustment() && "Not a parameter adjustment");
return ParameterAdjustmentIndex;
}
/// Determines whether the optional adjustment is an error.
bool isError() const {
switch (getKind()) {
case OptionalAdjustmentKind::None:
return false;
case OptionalAdjustmentKind::ProducesUnhandledNil:
case OptionalAdjustmentKind::ConsumesUnhandledNil:
return true;
case OptionalAdjustmentKind::WillNeverConsumeNil:
case OptionalAdjustmentKind::WillNeverProduceNil:
case OptionalAdjustmentKind::RemoveIUO:
case OptionalAdjustmentKind::IUOToOptional:
// Warnings at most.
return false;
}
llvm_unreachable("Unhandled OptionalAdjustmentKind in switch.");
}
/// Retrieve the source location at which the optional is
/// specified or would be inserted.
SourceLoc getOptionalityLoc(ValueDecl *witness) const;
/// Retrieve the optionality location for the given type
/// representation.
SourceLoc getOptionalityLoc(TypeRepr *tyR) const;
};
/// \brief Describes a match between a requirement and a witness.
struct RequirementMatch {
RequirementMatch(ValueDecl *witness, MatchKind kind,
Optional<RequirementEnvironment> &&env = None)
: Witness(witness), Kind(kind), WitnessType(), ReqEnv(std::move(env)) {
assert(!hasWitnessType() && "Should have witness type");
}
RequirementMatch(ValueDecl *witness, MatchKind kind,
Type witnessType,
Optional<RequirementEnvironment> &&env = None,
ArrayRef<OptionalAdjustment> optionalAdjustments = {})
: Witness(witness), Kind(kind), WitnessType(witnessType),
ReqEnv(std::move(env)),
OptionalAdjustments(optionalAdjustments.begin(),
optionalAdjustments.end())
{
assert(hasWitnessType() == !witnessType.isNull() &&
"Should (or should not) have witness type");
}
/// \brief The witness that matches the (implied) requirement.
ValueDecl *Witness;
/// \brief The kind of match.
MatchKind Kind;
/// \brief The type of the witness when it is referenced.
Type WitnessType;
/// \brief The requirement environment to use for the witness thunk.
Optional<RequirementEnvironment> ReqEnv;
/// The set of optional adjustments performed on the witness.
SmallVector<OptionalAdjustment, 2> OptionalAdjustments;
/// Substitutions mapping the type of the witness to the requirement
/// environment.
SmallVector<Substitution, 2> WitnessSubstitutions;
/// \brief Determine whether this match is viable.
bool isViable() const {
switch(Kind) {
case MatchKind::ExactMatch:
case MatchKind::OptionalityConflict:
case MatchKind::RenamedMatch:
return true;
case MatchKind::WitnessInvalid:
case MatchKind::KindConflict:
case MatchKind::TypeConflict:
case MatchKind::StaticNonStaticConflict:
case MatchKind::SettableConflict:
case MatchKind::PrefixNonPrefixConflict:
case MatchKind::PostfixNonPostfixConflict:
case MatchKind::MutatingConflict:
case MatchKind::NonMutatingConflict:
case MatchKind::ConsumingConflict:
case MatchKind::RethrowsConflict:
case MatchKind::ThrowsConflict:
case MatchKind::NonObjC:
return false;
}
llvm_unreachable("Unhandled MatchKind in switch.");
}
/// \brief Determine whether this requirement match has a witness type.
bool hasWitnessType() const {
switch(Kind) {
case MatchKind::ExactMatch:
case MatchKind::RenamedMatch:
case MatchKind::TypeConflict:
case MatchKind::OptionalityConflict:
return true;
case MatchKind::WitnessInvalid:
case MatchKind::KindConflict:
case MatchKind::StaticNonStaticConflict:
case MatchKind::SettableConflict:
case MatchKind::PrefixNonPrefixConflict:
case MatchKind::PostfixNonPostfixConflict:
case MatchKind::MutatingConflict:
case MatchKind::NonMutatingConflict:
case MatchKind::ConsumingConflict:
case MatchKind::RethrowsConflict:
case MatchKind::ThrowsConflict:
case MatchKind::NonObjC:
return false;
}
llvm_unreachable("Unhandled MatchKind in switch.");
}
swift::Witness getWitness(ASTContext &ctx) const;
};
struct RequirementCheck;
class WitnessChecker {
protected:
TypeChecker &TC;
ProtocolDecl *Proto;
Type Adoptee;
// The conforming context, either a nominal type or extension.
DeclContext *DC;
// An auxiliary lookup table to be used for witnesses remapped via
// @_implements(Protocol, DeclName)
llvm::DenseMap<DeclName, llvm::TinyPtrVector<ValueDecl *>> ImplementsTable;
WitnessChecker(TypeChecker &tc, ProtocolDecl *proto,
Type adoptee, DeclContext *dc);
/// Gather the value witnesses for the given requirement.
///
/// \param ignoringNames If non-null and there are no value
/// witnesses with the correct full name, the results will reflect
/// lookup for just the base name and the pointee will be set to
/// \c true.
SmallVector<ValueDecl *, 4> lookupValueWitnesses(ValueDecl *req,
bool *ignoringNames);
void lookupValueWitnessesViaImplementsAttr(ValueDecl *req,
SmallVector<ValueDecl *, 4>
&witnesses);
bool findBestWitness(ValueDecl *requirement,
bool *ignoringNames,
NormalProtocolConformance *conformance,
SmallVectorImpl<RequirementMatch> &matches,
unsigned &numViable,
unsigned &bestIdx,
bool &doNotDiagnoseMatches);
bool checkWitnessAccess(AccessScope &requiredAccessScope,
ValueDecl *requirement,
ValueDecl *witness,
bool *isSetter);
bool checkWitnessAvailability(ValueDecl *requirement,
ValueDecl *witness,
AvailabilityContext *requirementInfo);
RequirementCheck checkWitness(AccessScope requiredAccessScope,
ValueDecl *requirement,
const RequirementMatch &match);
};
/// The result of attempting to resolve a witness.
enum class ResolveWitnessResult {
/// The resolution succeeded.
Success,
/// There was an explicit witness available, but it failed some
/// criteria.
ExplicitFailed,
/// There was no witness available.
Missing
};
enum class MissingWitnessDiagnosisKind {
FixItOnly,
ErrorOnly,
ErrorFixIt,
};
class AssociatedTypeInference;
class MultiConformanceChecker;
/// The protocol conformance checker.
///
/// This helper class handles most of the details of checking whether a
/// given type (\c Adoptee) conforms to a protocol (\c Proto).
class ConformanceChecker : public WitnessChecker {
friend class MultiConformanceChecker;
friend class AssociatedTypeInference;
NormalProtocolConformance *Conformance;
SourceLoc Loc;
/// Witnesses that are currently being resolved.
llvm::SmallPtrSet<ValueDecl *, 4> ResolvingWitnesses;
/// Caches the set of associated types that are referenced in each
/// requirement.
llvm::DenseMap<ValueDecl *, llvm::SmallVector<AssociatedTypeDecl *, 2>>
ReferencedAssociatedTypes;
/// Keep track of missing witnesses, either type or value, for later
/// diagnosis emits. This may contain witnesses that are external to the
/// protocol under checking.
llvm::SetVector<ValueDecl*> &GlobalMissingWitnesses;
/// Keep track of the slice in GlobalMissingWitnesses that is local to
/// this protocol under checking.
unsigned LocalMissingWitnessesStartIndex;
/// True if we shouldn't complain about problems with this conformance
/// right now, i.e. if methods are being called outside
/// checkConformance().
bool SuppressDiagnostics;
/// Whether we've already complained about problems with this conformance.
bool AlreadyComplained = false;
/// Whether we checked the requirement signature already.
bool CheckedRequirementSignature = false;
/// Retrieve the associated types that are referenced by the given
/// requirement with a base of 'Self'.
ArrayRef<AssociatedTypeDecl *> getReferencedAssociatedTypes(ValueDecl *req);
/// Record a (non-type) witness for the given requirement.
void recordWitness(ValueDecl *requirement, const RequirementMatch &match);
/// Record that the given optional requirement has no witness.
void recordOptionalWitness(ValueDecl *requirement);
/// Record that the given requirement has no valid witness.
void recordInvalidWitness(ValueDecl *requirement);
/// Record a type witness.
///
/// \param assocType The associated type whose witness is being recorded.
///
/// \param type The witness type.
///
/// \param typeDecl The decl the witness type came from; can be null.
void recordTypeWitness(AssociatedTypeDecl *assocType, Type type,
TypeDecl *typeDecl, bool performRedeclarationCheck);
/// Enforce restrictions on non-final classes witnessing requirements
/// involving the protocol 'Self' type.
void checkNonFinalClassWitness(ValueDecl *requirement,
ValueDecl *witness);
/// Resolve a (non-type) witness via name lookup.
ResolveWitnessResult resolveWitnessViaLookup(ValueDecl *requirement);
/// Resolve a (non-type) witness via derivation.
ResolveWitnessResult resolveWitnessViaDerivation(ValueDecl *requirement);
/// Resolve a (non-type) witness via default definition or optional.
ResolveWitnessResult resolveWitnessViaDefault(ValueDecl *requirement);
/// Attempt to resolve a type witness via member name lookup.
ResolveWitnessResult resolveTypeWitnessViaLookup(
AssociatedTypeDecl *assocType);
/// Diagnose or defer a diagnostic, as appropriate.
///
/// \param requirement The requirement with which this diagnostic is
/// associated, if any.
///
/// \param isError Whether this diagnostic is an error.
///
/// \param fn A function to call to emit the actual diagnostic. If
/// diagnostics are being deferred,
void diagnoseOrDefer(
ValueDecl *requirement, bool isError,
std::function<void(NormalProtocolConformance *)> fn);
void
addUsedConformances(ProtocolConformance *conformance,
llvm::SmallPtrSetImpl<ProtocolConformance *> &visited);
void addUsedConformances(ProtocolConformance *conformance);
ArrayRef<ValueDecl*> getLocalMissingWitness() {
return GlobalMissingWitnesses.getArrayRef().
slice(LocalMissingWitnessesStartIndex,
GlobalMissingWitnesses.size() - LocalMissingWitnessesStartIndex);
}
void clearGlobalMissingWitnesses() {
GlobalMissingWitnesses.clear();
LocalMissingWitnessesStartIndex = GlobalMissingWitnesses.size();
}
public:
/// Call this to diagnose currently known missing witnesses.
void diagnoseMissingWitnesses(MissingWitnessDiagnosisKind Kind);
/// Emit any diagnostics that have been delayed.
void emitDelayedDiags();
ConformanceChecker(TypeChecker &tc, NormalProtocolConformance *conformance,
llvm::SetVector<ValueDecl*> &GlobalMissingWitnesses,
bool suppressDiagnostics = true);
/// Resolve all of the type witnesses.
void resolveTypeWitnesses();
/// Resolve the witness for the given non-type requirement as
/// directly as possible, only resolving other witnesses if
/// needed, e.g., to determine type witnesses used within the
/// requirement.
///
/// This entry point is designed to be used when the witness for a
/// particular requirement and adoptee is required, before the
/// conformance has been completed checked.
void resolveSingleWitness(ValueDecl *requirement);
/// Resolve the type witness for the given associated type as
/// directly as possible.
void resolveSingleTypeWitness(AssociatedTypeDecl *assocType);
/// Check all of the protocols requirements are actually satisfied by a
/// the chosen type witnesses.
///
/// \param failUnsubstituted Whether to fail when the requirements of the
/// protocol could not be substituted (e.g., due to missing information).
/// When true, emits a diagnostic in such cases; when false, enqueues the
/// conformance for later checking.
void ensureRequirementsAreSatisfied(bool failUnsubstituted);
/// Check the entire protocol conformance, ensuring that all
/// witnesses are resolved and emitting any diagnostics.
void checkConformance(MissingWitnessDiagnosisKind Kind);
};
/// Captures the state needed to infer associated types.
class AssociatedTypeInference {
/// The type checker we'll need to validate declarations etc.
TypeChecker &tc;
/// The conformance for which we are inferring associated types.
NormalProtocolConformance *conformance;
/// The protocol for which we are inferring associated types.
ProtocolDecl *proto;
/// The declaration context in which conformance to the protocol is
/// declared.
DeclContext *dc;
/// The type that is adopting the protocol.
Type adoptee;
/// The set of type witnesses inferred from value witnesses.
InferredAssociatedTypes inferred;
/// Hash table containing the type witnesses that we've inferred for
/// each associated type, as well as an indication of how we inferred them.
llvm::ScopedHashTable<AssociatedTypeDecl *, std::pair<Type, unsigned>>
typeWitnesses;
/// Information about a failed, defaulted associated type.
AssociatedTypeDecl *failedDefaultedAssocType = nullptr;
Type failedDefaultedWitness;
CheckTypeWitnessResult failedDefaultedResult;
/// Information about a failed, derived associated type.
AssociatedTypeDecl *failedDerivedAssocType = nullptr;
Type failedDerivedWitness;
// Which type witness was missing?
AssociatedTypeDecl *missingTypeWitness = nullptr;
// Was there a conflict in type witness deduction?
Optional<TypeWitnessConflict> typeWitnessConflict;
unsigned numTypeWitnessesBeforeConflict = 0;
public:
AssociatedTypeInference(TypeChecker &tc,
NormalProtocolConformance *conformance);
private:
/// Infer associated type witnesses for the given tentative
/// requirement/witness match.
InferredAssociatedTypesByWitness inferTypeWitnessesViaValueWitness(
ValueDecl *req,
ValueDecl *witness);
/// Infer associated type witnesses for the given value requirement.
InferredAssociatedTypesByWitnesses inferTypeWitnessesViaValueWitnesses(
ConformanceChecker &checker,
const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved,
ValueDecl *req);
/// Infer associated type witnesses for the given associated type.
InferredAssociatedTypesByWitnesses inferTypeWitnessesViaAssociatedType(
ConformanceChecker &checker,
const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved,
AssociatedTypeDecl *assocType);
/// Infer associated type witnesses for all relevant value requirements.
///
/// \param assocTypes The set of associated types we're interested in.
InferredAssociatedTypes
inferTypeWitnessesViaValueWitnesses(
ConformanceChecker &checker,
const llvm::SetVector<AssociatedTypeDecl *> &assocTypes);
/// Compute a "fixed" type witness for an associated type, e.g.,
/// if the refined protocol requires it to be equivalent to some other
/// concrete type.
Type computeFixedTypeWitness(AssociatedTypeDecl *assocType);
/// Compute the default type witness from an associated type default,
/// if there is one.
Type computeDefaultTypeWitness(AssociatedTypeDecl *assocType);
/// Compute the "derived" type witness for an associated type that is
/// known to the compiler.
Type computeDerivedTypeWitness(AssociatedTypeDecl *assocType);
/// Compute a type witness without using a specific potential witness,
/// e.g., using a fixed type (from a refined protocol), default type
/// on an associated type, or deriving the type.
///
/// \param allowDerived Whether to allow "derived" type witnesses.
Type computeAbstractTypeWitness(AssociatedTypeDecl *assocType,
bool allowDerived);
/// Substitute the current type witnesses into the given interface type.
Type substCurrentTypeWitnesses(Type type);
/// Retrieve substitution options with a tentative type witness
/// operation that queries the current set of type witnesses.
SubstOptions getSubstOptionsWithCurrentTypeWitnesses();
/// Check whether the current set of type witnesses meets the
/// requirements of the protocol.
bool checkCurrentTypeWitnesses(
const SmallVectorImpl<std::pair<ValueDecl *, ValueDecl *>>
&valueWitnesses);
/// Check the current type witnesses against the
/// requirements of the given constrained extension.
bool checkConstrainedExtension(ExtensionDecl *ext);
/// Top-level operation to find solutions for the given unresolved
/// associated types.
void findSolutions(
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes,
SmallVectorImpl<InferredTypeWitnessesSolution> &solutions);
/// Explore the solution space to find both viable and non-viable solutions.
void findSolutionsRec(
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes,
SmallVectorImpl<InferredTypeWitnessesSolution> &solutions,
SmallVectorImpl<InferredTypeWitnessesSolution> &nonViableSolutions,
SmallVector<std::pair<ValueDecl *, ValueDecl *>, 4> &valueWitnesses,
unsigned numTypeWitnesses,
unsigned numValueWitnessesInProtocolExtensions,
unsigned reqDepth);
/// Determine whether the first solution is better than the second
/// solution.
bool isBetterSolution(const InferredTypeWitnessesSolution &first,
const InferredTypeWitnessesSolution &second);
/// Find the best solution.
///
/// \param solutions All of the solutions to consider. On success,
/// this will contain only the best solution.
///
/// \returns \c false if there was a single best solution,
/// \c true if no single best solution exists.
bool findBestSolution(
SmallVectorImpl<InferredTypeWitnessesSolution> &solutions);
/// Emit a diagnostic for the case where there are no solutions at all
/// to consider.
///
/// \returns true if a diagnostic was emitted, false otherwise.
bool diagnoseNoSolutions(
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes,
ConformanceChecker &checker);
/// Emit a diagnostic when there are multiple solutions.
///
/// \returns true if a diagnostic was emitted, false otherwise.
bool diagnoseAmbiguousSolutions(
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes,
ConformanceChecker &checker,
SmallVectorImpl<InferredTypeWitnessesSolution> &solutions);
public:
/// Describes a mapping from associated type declarations to their
/// type witnesses (as interface types).
typedef std::vector<std::pair<AssociatedTypeDecl *, Type>>
InferredTypeWitnesses;
/// Perform associated type inference.
///
/// \returns \c true if an error occurred, \c false otherwise
Optional<InferredTypeWitnesses> solve(ConformanceChecker &checker);
};
/// \brief Match the given witness to the given requirement.
///
/// \returns the result of performing the match.
RequirementMatch matchWitness(
TypeChecker &tc,
DeclContext *dc, ValueDecl *req, ValueDecl *witness,
const std::function<
std::tuple<Optional<RequirementMatch>, Type, Type>(void)>
&setup,
const std::function<Optional<RequirementMatch>(Type, Type)>
&matchTypes,
const std::function<
RequirementMatch(bool, ArrayRef<OptionalAdjustment>)
> &finalize);
RequirementMatch matchWitness(TypeChecker &tc,
ProtocolDecl *proto,
ProtocolConformance *conformance,
DeclContext *dc,
ValueDecl *req,
ValueDecl *witness);
/// If the given type is a direct reference to an associated type of
/// the given protocol, return the referenced associated type.
AssociatedTypeDecl *getReferencedAssocTypeOfProtocol(Type type,
ProtocolDecl *proto);
}
#endif // SWIFT_SEMA_PROTOCOL_H