mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Diagnose redundant same-type constraints using most of the same machinery for diagnosing other redundant constraints. However, same-type constraints are particularly interesting because redundancies can be spelled in a number of different ways. Address this using the connected components of the subgraph involving only derived requirements (which is already used for the minimized generic signature). Then, separate all of the non-derived requirements into the intracomponent requirements and intercomponent requirements: * All of the intracomponent requirements are redundant by definition, because the components are defined by derived constraints. * For the intercomponent requirements, form a spanning tree among the various components and diagnose as redundant any edges that do not extend the spanning tree.
1491 lines
56 KiB
C++
1491 lines
56 KiB
C++
//===--- GenericSignatureBuilder.h - Generic signature builder --*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Support for collecting a set of generic requirements, whether they are
|
|
// explicitly stated, inferred from a type signature, or implied by other
|
|
// requirements, and computing the canonicalized, minimized generic signature
|
|
// from those requirements.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_GENERICSIGNATUREBUILDER_H
|
|
#define SWIFT_GENERICSIGNATUREBUILDER_H
|
|
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/DiagnosticEngine.h"
|
|
#include "swift/AST/Identifier.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/AST/TypeLoc.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/FoldingSet.h"
|
|
#include "llvm/ADT/PointerUnion.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/MapVector.h"
|
|
#include "llvm/ADT/TinyPtrVector.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/TrailingObjects.h"
|
|
#include <functional>
|
|
#include <memory>
|
|
|
|
namespace swift {
|
|
|
|
class DeclContext;
|
|
class DependentMemberType;
|
|
class GenericParamList;
|
|
class GenericSignature;
|
|
class GenericSignatureBuilder;
|
|
class GenericTypeParamType;
|
|
class LazyResolver;
|
|
class ModuleDecl;
|
|
class Pattern;
|
|
class ProtocolConformance;
|
|
class Requirement;
|
|
class RequirementRepr;
|
|
class SILModule;
|
|
class SourceLoc;
|
|
class SubstitutionMap;
|
|
class Type;
|
|
class TypeRepr;
|
|
class ASTContext;
|
|
class DiagnosticEngine;
|
|
|
|
/// \brief Collects a set of requirements of generic parameters, both explicitly
|
|
/// stated and inferred, and determines the set of archetypes for each of
|
|
/// the generic parameters.
|
|
class GenericSignatureBuilder {
|
|
public:
|
|
/// Describes a potential archetype, which stands in for a generic parameter
|
|
/// type or some type derived from it.
|
|
class PotentialArchetype;
|
|
|
|
using UnresolvedType = llvm::PointerUnion<PotentialArchetype *, Type>;
|
|
struct ResolvedType;
|
|
|
|
using RequirementRHS =
|
|
llvm::PointerUnion3<Type, PotentialArchetype *, LayoutConstraint>;
|
|
|
|
/// The location of a requirement as written somewhere in the source.
|
|
typedef llvm::PointerUnion<const TypeRepr *, const RequirementRepr *>
|
|
WrittenRequirementLoc;
|
|
|
|
class RequirementSource;
|
|
|
|
class FloatingRequirementSource;
|
|
|
|
/// Describes a specific constraint on a potential archetype.
|
|
template<typename T>
|
|
struct Constraint {
|
|
PotentialArchetype *archetype;
|
|
T value;
|
|
const RequirementSource *source;
|
|
};
|
|
|
|
/// Describes a concrete constraint on a potential archetype where, where the
|
|
/// other parameter is a concrete type.
|
|
typedef Constraint<Type> ConcreteConstraint;
|
|
|
|
/// Describes an equivalence class of potential archetypes.
|
|
struct EquivalenceClass {
|
|
/// The list of protocols to which this equivalence class conforms.
|
|
///
|
|
/// The keys form the (semantic) list of protocols to which this type
|
|
/// conforms. The values are the conformance constraints as written on
|
|
/// this equivalence class.
|
|
llvm::MapVector<ProtocolDecl *, std::vector<Constraint<ProtocolDecl *>>>
|
|
conformsTo;
|
|
|
|
/// Same-type constraints between each potential archetype and any other
|
|
/// archetype in its equivalence class.
|
|
llvm::MapVector<PotentialArchetype *,
|
|
std::vector<Constraint<PotentialArchetype *>>>
|
|
sameTypeConstraints;
|
|
|
|
/// Concrete type to which this equivalence class is equal.
|
|
///
|
|
/// This is the semantic concrete type; the constraints as written
|
|
/// (or implied) are stored in \c concreteTypeConstraints;
|
|
Type concreteType;
|
|
|
|
/// The same-type-to-concrete constraints written within this
|
|
/// equivalence class.
|
|
std::vector<ConcreteConstraint> concreteTypeConstraints;
|
|
|
|
/// Superclass constraint, which requires that the type fulfilling the
|
|
/// requirements of this equivalence class to be the same as or a subtype
|
|
/// of this superclass.
|
|
Type superclass;
|
|
|
|
/// Superclass constraints written within this equivalence class.
|
|
std::vector<ConcreteConstraint> superclassConstraints;
|
|
|
|
/// \The layout constraint for this equivalence class.
|
|
LayoutConstraint layout;
|
|
|
|
/// Layout constraints written within this equivalence class.
|
|
std::vector<Constraint<LayoutConstraint>> layoutConstraints;
|
|
|
|
/// The members of the equivalence class.
|
|
TinyPtrVector<PotentialArchetype *> members;
|
|
|
|
/// Describes a component within the graph of same-type constraints within
|
|
/// the equivalence class that is held together by derived constraints.
|
|
struct DerivedSameTypeComponent {
|
|
/// The potential archetype that acts as the anchor for this component.
|
|
PotentialArchetype *anchor;
|
|
|
|
/// The (best) requirement source within the component that makes the
|
|
/// potential archetypes in this component equivalent to the concrete
|
|
/// type.
|
|
const RequirementSource *concreteTypeSource;
|
|
};
|
|
|
|
/// The set of connected components within this equivalence class, using
|
|
/// only the derived same-type constraints in the graph.
|
|
std::vector<DerivedSameTypeComponent> derivedSameTypeComponents;
|
|
|
|
/// Construct a new equivalence class containing only the given
|
|
/// potential archetype (which represents itself).
|
|
EquivalenceClass(PotentialArchetype *representative);
|
|
|
|
/// Find a source of the same-type constraint that maps a potential
|
|
/// archetype in this equivalence class to a concrete type along with
|
|
/// that concrete type as written.
|
|
Optional<ConcreteConstraint>
|
|
findAnyConcreteConstraintAsWritten(
|
|
PotentialArchetype *preferredPA = nullptr) const;
|
|
|
|
/// Find a source of the superclass constraint in this equivalence class
|
|
/// that has a type equivalence to \c superclass, along with that
|
|
/// superclass type as written.
|
|
Optional<ConcreteConstraint>
|
|
findAnySuperclassConstraintAsWritten(
|
|
PotentialArchetype *preferredPA = nullptr) const;
|
|
|
|
/// Determine whether conformance to the given protocol is satisfied by
|
|
/// a superclass requirement.
|
|
bool isConformanceSatisfiedBySuperclass(ProtocolDecl *proto) const;
|
|
};
|
|
|
|
friend class RequirementSource;
|
|
|
|
private:
|
|
class InferRequirementsWalker;
|
|
friend class InferRequirementsWalker;
|
|
friend class GenericSignature;
|
|
|
|
ASTContext &Context;
|
|
DiagnosticEngine &Diags;
|
|
struct Implementation;
|
|
std::unique_ptr<Implementation> Impl;
|
|
|
|
GenericSignatureBuilder(const GenericSignatureBuilder &) = delete;
|
|
GenericSignatureBuilder &operator=(const GenericSignatureBuilder &) = delete;
|
|
|
|
/// Retrieve the constraint source conformance for the superclass constraint
|
|
/// of the given potential archetype (if present) to the given protocol.
|
|
///
|
|
/// \param pa The potential archetype whose superclass constraint is being
|
|
/// queried.
|
|
///
|
|
/// \param proto The protocol to which we are establishing conformance.
|
|
const RequirementSource *resolveSuperConformance(
|
|
GenericSignatureBuilder::PotentialArchetype *pa,
|
|
ProtocolDecl *proto);
|
|
|
|
/// \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);
|
|
|
|
bool 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
|
|
/// (output of \c GenericSignatureBuilder::resolve).
|
|
///
|
|
/// If the types refer to two concrete types that are fundamentally
|
|
/// 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
|
|
addSameTypeRequirement(ResolvedType paOrT1, ResolvedType paOrT2,
|
|
FloatingRequirementSource Source,
|
|
llvm::function_ref<void(Type, Type)> diagnoseMismatch);
|
|
|
|
/// \brief Add a new same-type requirement between two fully resolved types
|
|
/// (output of GenericSignatureBuilder::resolve).
|
|
///
|
|
/// The two types must not be incompatible concrete types.
|
|
bool addSameTypeRequirement(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);
|
|
|
|
/// \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
|
|
addSameTypeRequirement(UnresolvedType paOrT1, UnresolvedType paOrT2,
|
|
FloatingRequirementSource Source,
|
|
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,
|
|
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 addSuperclassRequirement(PotentialArchetype *T,
|
|
Type Superclass,
|
|
const RequirementSource *Source);
|
|
|
|
/// \brief Add a new conformance requirement specifying that the given
|
|
/// potential archetypes are equivalent.
|
|
bool 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,
|
|
Type Concrete,
|
|
const RequirementSource *Source);
|
|
|
|
/// \brief Add a new same-type requirement specifying that the given two
|
|
/// types should be the same.
|
|
///
|
|
/// \param diagnoseMismatch Callback invoked when the types in the same-type
|
|
/// requirement mismatch.
|
|
bool addSameTypeRequirementBetweenConcrete(
|
|
Type T1, Type T2, FloatingRequirementSource Source,
|
|
llvm::function_ref<void(Type, Type)> diagnoseMismatch);
|
|
|
|
/// Add the requirements placed on the given type parameter
|
|
/// to the given potential archetype.
|
|
///
|
|
/// \param dependentType A dependent type thar describes \c pa relative to
|
|
/// its protocol, for protocol requirements.
|
|
///
|
|
/// FIXME: \c dependentType will be derivable from \c parentSource and \c pa
|
|
/// when we're no longer putting conformance requirements directly on the
|
|
/// representative.
|
|
bool addInheritedRequirements(TypeDecl *decl, PotentialArchetype *pa,
|
|
Type dependentType,
|
|
const RequirementSource *parentSource,
|
|
llvm::SmallPtrSetImpl<ProtocolDecl *> &visited);
|
|
|
|
/// Visit all of the potential archetypes.
|
|
template<typename F>
|
|
void visitPotentialArchetypes(F f);
|
|
|
|
void markPotentialArchetypeRecursive(PotentialArchetype *pa,
|
|
ProtocolDecl *proto,
|
|
const RequirementSource *source);
|
|
|
|
public:
|
|
/// Construct a new generic signature builder.
|
|
///
|
|
/// \param lookupConformance Conformance-lookup routine that will be used
|
|
/// to satisfy conformance requirements for concrete types.
|
|
explicit GenericSignatureBuilder(ASTContext &ctx,
|
|
std::function<GenericFunction> lookupConformance);
|
|
|
|
GenericSignatureBuilder(GenericSignatureBuilder &&);
|
|
~GenericSignatureBuilder();
|
|
|
|
/// Retrieve the AST context.
|
|
ASTContext &getASTContext() const { return Context; }
|
|
|
|
/// Retrieve the conformance-lookup function used by this generic signature builder.
|
|
std::function<GenericFunction> getLookupConformanceFn() const;
|
|
|
|
/// Retrieve the lazy resolver, if there is one.
|
|
LazyResolver *getLazyResolver() const;
|
|
|
|
/// Enumerate the requirements that describe the signature of this
|
|
/// generic signature builder.
|
|
///
|
|
/// \param f A function object that will be passed each requirement
|
|
/// and requirement source.
|
|
void enumerateRequirements(llvm::function_ref<
|
|
void (RequirementKind kind,
|
|
PotentialArchetype *archetype,
|
|
RequirementRHS constraint,
|
|
const RequirementSource *source)> f);
|
|
|
|
public:
|
|
/// \brief Add a new generic parameter for which there may be requirements.
|
|
void addGenericParameter(GenericTypeParamDecl *GenericParam);
|
|
|
|
/// Add the requirements placed on the given abstract type parameter
|
|
/// to the given potential archetype.
|
|
///
|
|
/// \returns true if an error occurred, false otherwise.
|
|
bool addGenericParameterRequirements(GenericTypeParamDecl *GenericParam);
|
|
|
|
/// \brief Add a new generic parameter for which there may be requirements.
|
|
void addGenericParameter(GenericTypeParamType *GenericParam);
|
|
|
|
/// \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);
|
|
|
|
/// \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);
|
|
|
|
/// \brief Add an already-checked requirement.
|
|
///
|
|
/// Adding an already-checked requirement cannot fail. This is used to
|
|
/// re-inject requirements from outer contexts.
|
|
///
|
|
/// \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);
|
|
|
|
/// \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 addLayoutRequirement(PotentialArchetype *PAT,
|
|
LayoutConstraint Layout,
|
|
const RequirementSource *Source);
|
|
|
|
/// \brief Add all of a generic signature's parameters and requirements.
|
|
void addGenericSignature(GenericSignature *sig);
|
|
|
|
/// \brief Build the generic signature.
|
|
GenericSignature *getGenericSignature();
|
|
|
|
/// Infer requirements from the given type, recursively.
|
|
///
|
|
/// This routine infers requirements from a type that occurs within the
|
|
/// signature of a generic function. For example, given:
|
|
///
|
|
/// \code
|
|
/// func f<K, V>(dict : Dictionary<K, V>) { ... }
|
|
/// \endcode
|
|
///
|
|
/// where \c Dictionary requires that its key type be \c Hashable,
|
|
/// the requirement \c K : Hashable is inferred from the parameter type,
|
|
/// because the type \c Dictionary<K,V> cannot be formed without it.
|
|
void inferRequirements(ModuleDecl &module, TypeLoc type);
|
|
|
|
/// Infer requirements from the given pattern, recursively.
|
|
///
|
|
/// This routine infers requirements from a type that occurs within the
|
|
/// signature of a generic function. For example, given:
|
|
///
|
|
/// \code
|
|
/// func f<K, V>(dict : Dictionary<K, V>) { ... }
|
|
/// \endcode
|
|
///
|
|
/// where \c Dictionary requires that its key type be \c Hashable,
|
|
/// the requirement \c K : Hashable is inferred from the parameter type,
|
|
/// because the type \c Dictionary<K,V> cannot be formed without it.
|
|
void inferRequirements(ModuleDecl &module, ParameterList *params,
|
|
GenericParamList *genericParams);
|
|
|
|
/// Finalize the set of requirements, performing any remaining checking
|
|
/// required before generating archetypes.
|
|
///
|
|
/// \param allowConcreteGenericParams If true, allow generic parameters to
|
|
/// be made concrete.
|
|
void finalize(SourceLoc loc,
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
bool allowConcreteGenericParams=false);
|
|
|
|
/// Diagnose any remaining renames.
|
|
///
|
|
/// \returns \c true if there were any remaining renames to diagnose.
|
|
bool diagnoseRemainingRenames(SourceLoc loc,
|
|
ArrayRef<GenericTypeParamType *> genericParams);
|
|
|
|
private:
|
|
/// Describes the relationship between a given constraint and
|
|
/// the canonical constraint of the equivalence class.
|
|
enum class ConstraintRelation {
|
|
/// The constraint is unrelated.
|
|
///
|
|
/// This is a conservative result that can be used when, for example,
|
|
/// we have incomplete information to make a determination.
|
|
Unrelated,
|
|
/// The constraint is redundant and can be removed without affecting the
|
|
/// semantics.
|
|
Redundant,
|
|
/// The constraint conflicts, meaning that the signature is erroneous.
|
|
Conflicting,
|
|
};
|
|
|
|
/// Check a list of constraints, removing self-derived constraints
|
|
/// and diagnosing redundant constraints.
|
|
///
|
|
/// \param isSuitableRepresentative Determines whether the given constraint
|
|
/// is a suitable representative.
|
|
///
|
|
/// \param checkConstraint Checks the given constraint against the
|
|
/// canonical constraint to determine which diagnostics (if any) should be
|
|
/// emitted.
|
|
///
|
|
/// \returns the representative constraint.
|
|
template<typename T>
|
|
Constraint<T> checkConstraintList(
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
std::vector<Constraint<T>> &constraints,
|
|
llvm::function_ref<bool(const Constraint<T> &)>
|
|
isSuitableRepresentative,
|
|
llvm::function_ref<ConstraintRelation(const T&)>
|
|
checkConstraint,
|
|
Optional<Diag<unsigned, Type, T, T>>
|
|
conflictingDiag,
|
|
Diag<Type, T> redundancyDiag,
|
|
Diag<bool, Type, T> otherNoteDiag);
|
|
|
|
/// Check a list of constraints, removing self-derived constraints
|
|
/// and diagnosing redundant constraints.
|
|
///
|
|
/// \param isSuitableRepresentative Determines whether the given constraint
|
|
/// is a suitable representative.
|
|
///
|
|
/// \param checkConstraint Checks the given constraint against the
|
|
/// canonical constraint to determine which diagnostics (if any) should be
|
|
/// emitted.
|
|
///
|
|
/// \returns the representative constraint.
|
|
template<typename T, typename DiagT>
|
|
Constraint<T> checkConstraintList(
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
std::vector<Constraint<T>> &constraints,
|
|
llvm::function_ref<bool(const Constraint<T> &)>
|
|
isSuitableRepresentative,
|
|
llvm::function_ref<ConstraintRelation(const T&)>
|
|
checkConstraint,
|
|
Optional<Diag<unsigned, Type, DiagT, DiagT>>
|
|
conflictingDiag,
|
|
Diag<Type, DiagT> redundancyDiag,
|
|
Diag<bool, Type, DiagT> otherNoteDiag,
|
|
llvm::function_ref<DiagT(const T&)> diagValue,
|
|
bool removeSelfDerived);
|
|
|
|
/// Check the concrete type constraints within the equivalence
|
|
/// class of the given potential archetype.
|
|
void checkConcreteTypeConstraints(
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
PotentialArchetype *pa);
|
|
|
|
/// Check the superclass constraints within the equivalence
|
|
/// class of the given potential archetype.
|
|
void checkSuperclassConstraints(
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
PotentialArchetype *pa);
|
|
|
|
/// Check conformance constraints within the equivalence class of the
|
|
/// given potential archetype.
|
|
void checkConformanceConstraints(
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
PotentialArchetype *pa);
|
|
|
|
/// Check layout constraints within the equivalence class of the given
|
|
/// potential archetype.
|
|
void checkLayoutConstraints(ArrayRef<GenericTypeParamType *> genericParams,
|
|
PotentialArchetype *pa);
|
|
|
|
/// Check same-type constraints within the equivalence class of the
|
|
/// given potential archetype.
|
|
void checkSameTypeConstraints(
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
PotentialArchetype *pa);
|
|
|
|
public:
|
|
/// \brief Resolve the given type to the potential archetype it names.
|
|
///
|
|
/// This routine will synthesize nested types as required to refer to a
|
|
/// potential archetype, even in cases where no requirement specifies the
|
|
/// requirement for such an archetype. FIXME: The failure to include such a
|
|
/// requirement will be diagnosed at some point later (when the types in the
|
|
/// signature are fully resolved).
|
|
///
|
|
/// For any type that cannot refer to an archetype, this routine returns null.
|
|
PotentialArchetype *resolveArchetype(Type type);
|
|
|
|
/// \brief Resolve the given type as far as this Builder knows how.
|
|
///
|
|
/// This returns either a non-typealias potential archetype or a Type, if \c
|
|
/// type is concrete.
|
|
// FIXME: the hackTypeFromGenericTypeAlias is just temporarily patching over
|
|
// problems with generic typealiases (see the comment on the ResolvedType
|
|
// function)
|
|
ResolvedType resolve(UnresolvedType type,
|
|
bool hackTypeFromGenericTypeAlias = false);
|
|
|
|
/// \brief Dump all of the requirements, both specified and inferred.
|
|
LLVM_ATTRIBUTE_DEPRECATED(
|
|
void dump(),
|
|
"only for use within the debugger");
|
|
|
|
/// Dump all of the requirements to the given output stream.
|
|
void dump(llvm::raw_ostream &out);
|
|
};
|
|
|
|
/// Describes how a generic signature determines a requirement, from its origin
|
|
/// in some requirement written in the source, inferred through a path of
|
|
/// other implications (e.g., introduced by a particular protocol).
|
|
///
|
|
/// Requirement sources are uniqued within a generic signature builder.
|
|
class GenericSignatureBuilder::RequirementSource final
|
|
: public llvm::FoldingSetNode,
|
|
private llvm::TrailingObjects<RequirementSource, ProtocolDecl *,
|
|
WrittenRequirementLoc> {
|
|
|
|
friend class FloatingRequirementSource;
|
|
friend class GenericSignature;
|
|
|
|
public:
|
|
enum Kind : uint8_t {
|
|
/// A requirement stated explicitly, e.g., in a where clause or type
|
|
/// parameter declaration.
|
|
///
|
|
/// Explicitly-stated requirement can be tied to a specific requirement
|
|
/// in a 'where' clause (which stores a \c RequirementRepr), a type in an
|
|
/// 'inheritance' clause (which stores a \c TypeRepr), or can be 'abstract',
|
|
/// , e.g., due to canonicalization, deserialization, or other
|
|
/// source-independent formulation.
|
|
///
|
|
/// This is a root requirement source.
|
|
Explicit,
|
|
|
|
/// A requirement inferred from part of the signature of a declaration,
|
|
/// e.g., the type of a generic function. For example:
|
|
///
|
|
/// func f<T>(_: Set<T>) { } // infers T: Hashable
|
|
///
|
|
/// This is a root requirement source, which can be described by a
|
|
/// \c TypeRepr.
|
|
Inferred,
|
|
|
|
/// A requirement for the creation of the requirement signature of a
|
|
/// protocol.
|
|
///
|
|
/// This is a root requirement source, which is described by the protocol
|
|
/// whose requirement signature is being computed.
|
|
RequirementSignatureSelf,
|
|
|
|
/// The requirement came from two nested types of the equivalent types whose
|
|
/// names match.
|
|
///
|
|
/// This is a root requirement source.
|
|
NestedTypeNameMatch,
|
|
|
|
/// The requirement is a protocol requirement.
|
|
///
|
|
/// This stores the protocol that introduced the requirement as well as the
|
|
/// dependent type (relative to that protocol) to which the conformance
|
|
/// appertains.
|
|
ProtocolRequirement,
|
|
|
|
/// A requirement that was resolved via a superclass requirement.
|
|
///
|
|
/// This stores the \c ProtocolConformance* used to resolve the
|
|
/// requirement.
|
|
Superclass,
|
|
|
|
/// A requirement that was resolved for a nested type via its parent
|
|
/// type.
|
|
Parent,
|
|
|
|
/// A requirement that was resolved for a nested type via a same-type-to-
|
|
/// concrete constraint.
|
|
///
|
|
/// This stores the \c ProtocolConformance* used to resolve the
|
|
/// requirement.
|
|
Concrete,
|
|
};
|
|
|
|
/// The kind of requirement source.
|
|
const Kind kind;
|
|
|
|
private:
|
|
/// The kind of storage we have.
|
|
enum class StorageKind : uint8_t {
|
|
RootArchetype,
|
|
StoredType,
|
|
ProtocolConformance,
|
|
AssociatedTypeDecl,
|
|
};
|
|
|
|
/// The kind of storage we have.
|
|
const StorageKind storageKind;
|
|
|
|
/// Whether there is a trailing written requirement location.
|
|
const bool hasTrailingWrittenRequirementLoc;
|
|
|
|
/// Whether a protocol requirement came from the requirement signature.
|
|
const bool usesRequirementSignature;
|
|
|
|
/// The actual storage, described by \c storageKind.
|
|
union {
|
|
/// The root archetype.
|
|
PotentialArchetype *rootArchetype;
|
|
|
|
/// The type to which a requirement applies.
|
|
TypeBase *type;
|
|
|
|
/// A protocol conformance used to satisfy the requirement.
|
|
ProtocolConformance *conformance;
|
|
|
|
/// An associated type to which a requirement is being applied.
|
|
AssociatedTypeDecl *assocType;
|
|
} storage;
|
|
|
|
friend TrailingObjects;
|
|
|
|
/// The trailing protocol declaration, if there is one.
|
|
size_t numTrailingObjects(OverloadToken<ProtocolDecl *>) const {
|
|
switch (kind) {
|
|
case RequirementSignatureSelf:
|
|
case ProtocolRequirement:
|
|
return 1;
|
|
|
|
case Explicit:
|
|
case Inferred:
|
|
case NestedTypeNameMatch:
|
|
case Superclass:
|
|
case Parent:
|
|
case Concrete:
|
|
return 0;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled RequirementSourceKind in switch.");
|
|
}
|
|
|
|
/// The trailing written requirement location, if there is one.
|
|
size_t numTrailingObjects(OverloadToken<WrittenRequirementLoc>) const {
|
|
return hasTrailingWrittenRequirementLoc ? 1 : 0;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
/// Determines whether we have been provided with an acceptable storage kind
|
|
/// for the given requirement source kind.
|
|
static bool isAcceptableStorageKind(Kind kind, StorageKind storageKind);
|
|
#endif
|
|
|
|
/// Retrieve the opaque storage as a single pointer, for use in uniquing.
|
|
const void *getOpaqueStorage1() const;
|
|
|
|
/// Retrieve the second opaque storage as a single pointer, for use in
|
|
/// uniquing.
|
|
const void *getOpaqueStorage2() const;
|
|
|
|
/// Retrieve the third opaque storage as a single pointer, for use in
|
|
/// uniquing.
|
|
const void *getOpaqueStorage3() const;
|
|
|
|
/// Whether this kind of requirement source is a root.
|
|
static bool isRootKind(Kind kind) {
|
|
switch (kind) {
|
|
case Explicit:
|
|
case Inferred:
|
|
case RequirementSignatureSelf:
|
|
case NestedTypeNameMatch:
|
|
return true;
|
|
|
|
case ProtocolRequirement:
|
|
case Superclass:
|
|
case Parent:
|
|
case Concrete:
|
|
return false;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled RequirementSourceKind in switch.");
|
|
}
|
|
|
|
public:
|
|
/// The "parent" of this requirement source.
|
|
///
|
|
/// The chain of parent requirement sources will eventually terminate in a
|
|
/// requirement source with one of the "root" kinds.
|
|
const RequirementSource * const parent;
|
|
|
|
RequirementSource(Kind kind, PotentialArchetype *rootArchetype,
|
|
ProtocolDecl *protocol,
|
|
WrittenRequirementLoc writtenReqLoc)
|
|
: kind(kind), storageKind(StorageKind::RootArchetype),
|
|
hasTrailingWrittenRequirementLoc(!writtenReqLoc.isNull()),
|
|
usesRequirementSignature(false), parent(nullptr) {
|
|
assert(isAcceptableStorageKind(kind, storageKind) &&
|
|
"RequirementSource kind/storageKind mismatch");
|
|
|
|
storage.rootArchetype = rootArchetype;
|
|
if (kind == RequirementSignatureSelf)
|
|
getTrailingObjects<ProtocolDecl *>()[0] = protocol;
|
|
if (hasTrailingWrittenRequirementLoc)
|
|
getTrailingObjects<WrittenRequirementLoc>()[0] = writtenReqLoc;
|
|
}
|
|
|
|
RequirementSource(Kind kind, const RequirementSource *parent,
|
|
Type type, ProtocolDecl *protocol,
|
|
WrittenRequirementLoc writtenReqLoc)
|
|
: kind(kind), storageKind(StorageKind::StoredType),
|
|
hasTrailingWrittenRequirementLoc(!writtenReqLoc.isNull()),
|
|
usesRequirementSignature(protocol->isRequirementSignatureComputed()),
|
|
parent(parent) {
|
|
assert((static_cast<bool>(parent) != isRootKind(kind)) &&
|
|
"Root RequirementSource should not have parent (or vice versa)");
|
|
assert(isAcceptableStorageKind(kind, storageKind) &&
|
|
"RequirementSource kind/storageKind mismatch");
|
|
|
|
storage.type = type.getPointer();
|
|
if (kind == ProtocolRequirement)
|
|
getTrailingObjects<ProtocolDecl *>()[0] = protocol;
|
|
if (hasTrailingWrittenRequirementLoc)
|
|
getTrailingObjects<WrittenRequirementLoc>()[0] = writtenReqLoc;
|
|
}
|
|
|
|
RequirementSource(Kind kind, const RequirementSource *parent,
|
|
ProtocolConformance *conformance)
|
|
: kind(kind), storageKind(StorageKind::ProtocolConformance),
|
|
hasTrailingWrittenRequirementLoc(false),
|
|
usesRequirementSignature(false), parent(parent) {
|
|
assert((static_cast<bool>(parent) != isRootKind(kind)) &&
|
|
"Root RequirementSource should not have parent (or vice versa)");
|
|
assert(isAcceptableStorageKind(kind, storageKind) &&
|
|
"RequirementSource kind/storageKind mismatch");
|
|
|
|
storage.conformance = conformance;
|
|
}
|
|
|
|
RequirementSource(Kind kind, const RequirementSource *parent,
|
|
AssociatedTypeDecl *assocType)
|
|
: kind(kind), storageKind(StorageKind::AssociatedTypeDecl),
|
|
hasTrailingWrittenRequirementLoc(false),
|
|
usesRequirementSignature(false), parent(parent) {
|
|
assert((static_cast<bool>(parent) != isRootKind(kind)) &&
|
|
"Root RequirementSource should not have parent (or vice versa)");
|
|
assert(isAcceptableStorageKind(kind, storageKind) &&
|
|
"RequirementSource kind/storageKind mismatch");
|
|
|
|
storage.assocType = assocType;
|
|
}
|
|
|
|
public:
|
|
/// Retrieve an abstract requirement source.
|
|
static const RequirementSource *forAbstract(PotentialArchetype *root);
|
|
|
|
/// Retrieve a requirement source representing an explicit requirement
|
|
/// stated in an 'inheritance' or 'where' clause.
|
|
static const RequirementSource *forExplicit(PotentialArchetype *root,
|
|
WrittenRequirementLoc writtenLoc);
|
|
|
|
/// Retrieve a requirement source representing a requirement that is
|
|
/// inferred from some part of a generic declaration's signature, e.g., the
|
|
/// parameter or result type of a generic function.
|
|
static const RequirementSource *forInferred(PotentialArchetype *root,
|
|
const TypeRepr *typeRepr);
|
|
|
|
/// Retrieve a requirement source representing the requirement signature
|
|
/// computation for a protocol.
|
|
static const RequirementSource *forRequirementSignature(
|
|
PotentialArchetype *root,
|
|
ProtocolDecl *protocol);
|
|
|
|
/// Retrieve a requirement source for nested type name matches.
|
|
static const RequirementSource *forNestedTypeNameMatch(
|
|
PotentialArchetype *root);
|
|
|
|
private:
|
|
/// A requirement source that describes that a requirement comes from a
|
|
/// requirement of the given protocol described by the parent.
|
|
const RequirementSource *viaProtocolRequirement(
|
|
GenericSignatureBuilder &builder,
|
|
Type dependentType,
|
|
ProtocolDecl *protocol,
|
|
WrittenRequirementLoc writtenLoc =
|
|
WrittenRequirementLoc()) const;
|
|
|
|
public:
|
|
/// A requirement source that describes that a requirement that is resolved
|
|
/// via a superclass requirement.
|
|
const RequirementSource *viaSuperclass(
|
|
GenericSignatureBuilder &builder,
|
|
ProtocolConformance *conformance) const;
|
|
|
|
/// A requirement source that describes that a requirement that is resolved
|
|
/// via a same-type-to-concrete requirement.
|
|
const RequirementSource *viaConcrete(GenericSignatureBuilder &builder,
|
|
ProtocolConformance *conformance) const;
|
|
|
|
/// A constraint source that describes that a constraint that is resolved
|
|
/// for a nested type via a constraint on its parent.
|
|
///
|
|
/// \param assocType the associated type that
|
|
const RequirementSource *viaParent(GenericSignatureBuilder &builder,
|
|
AssociatedTypeDecl *assocType) const;
|
|
|
|
/// Retrieve the root requirement source.
|
|
const RequirementSource *getRoot() const;
|
|
|
|
/// Retrieve the potential archetype at the root.
|
|
PotentialArchetype *getRootPotentialArchetype() const;
|
|
|
|
/// Whether the requirement is inferred or derived from an inferred
|
|
/// requirment.
|
|
bool isInferredRequirement() const {
|
|
return getRoot()->kind == Inferred;
|
|
}
|
|
|
|
/// Whether the requirement can be derived from something in its path.
|
|
///
|
|
/// Derived requirements will not be recorded in a minimized generic
|
|
/// signature, because the information can be re-derived by following the
|
|
/// path.
|
|
bool isDerivedRequirement() const;
|
|
|
|
/// Whether the requirement is derived via some concrete conformance, e.g.,
|
|
/// a concrete type's conformance to a protocol or a superclass's conformance
|
|
/// to a protocol.
|
|
bool isDerivedViaConcreteConformance() const;
|
|
|
|
/// Determine whether the given derived requirement \c source, when rooted at
|
|
/// the potential archetype \c pa, is actually derived from the same
|
|
/// requirement. Such "self-derived" requirements do not make the original
|
|
/// requirement redundant, because without said original requirement, the
|
|
/// derived requirement ceases to hold.
|
|
bool isSelfDerivedSource(PotentialArchetype *pa) const;
|
|
|
|
/// Retrieve a source location that corresponds to the requirement.
|
|
SourceLoc getLoc() const;
|
|
|
|
/// Compare two requirement sources to determine which has the more
|
|
/// optimal path.
|
|
///
|
|
/// \returns -1 if the \c this is better, 1 if the \c other is better, and 0
|
|
/// if they are equivalent in length.
|
|
int compare(const RequirementSource *other) const;
|
|
|
|
/// Retrieve the type representation for this requirement, if there is one.
|
|
const TypeRepr *getTypeRepr() const {
|
|
if (!hasTrailingWrittenRequirementLoc) return nullptr;
|
|
return getTrailingObjects<WrittenRequirementLoc>()[0]
|
|
.dyn_cast<const TypeRepr *>();
|
|
}
|
|
|
|
/// Retrieve the requirement representation for this requirement, if there is
|
|
/// one.
|
|
const RequirementRepr *getRequirementRepr() const {
|
|
if (!hasTrailingWrittenRequirementLoc) return nullptr;
|
|
return getTrailingObjects<WrittenRequirementLoc>()[0]
|
|
.dyn_cast<const RequirementRepr *>();
|
|
}
|
|
|
|
/// Retrieve the type stored in this requirement.
|
|
Type getStoredType() const;
|
|
|
|
/// Retrieve the protocol for this requirement, if there is one.
|
|
ProtocolDecl *getProtocolDecl() const;
|
|
|
|
/// Retrieve the protocol conformance for this requirement, if there is one.
|
|
ProtocolConformance *getProtocolConformance() const {
|
|
if (storageKind != StorageKind::ProtocolConformance) return nullptr;
|
|
return storage.conformance;
|
|
}
|
|
|
|
/// Retrieve the associated type declaration for this requirement, if there
|
|
/// is one.
|
|
AssociatedTypeDecl *getAssociatedType() const {
|
|
if (storageKind != StorageKind::AssociatedTypeDecl) return nullptr;
|
|
return storage.assocType;
|
|
}
|
|
|
|
/// Profiling support for \c FoldingSet.
|
|
void Profile(llvm::FoldingSetNodeID &ID) {
|
|
Profile(ID, kind, parent, getOpaqueStorage1(), getOpaqueStorage2(),
|
|
getOpaqueStorage3());
|
|
}
|
|
|
|
/// Profiling support for \c FoldingSet.
|
|
static void Profile(llvm::FoldingSetNodeID &ID, Kind kind,
|
|
const RequirementSource *parent, const void *storage1,
|
|
const void *storage2, const void *storage3) {
|
|
ID.AddInteger(kind);
|
|
ID.AddPointer(parent);
|
|
ID.AddPointer(storage1);
|
|
ID.AddPointer(storage2);
|
|
ID.AddPointer(storage3);
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_DEPRECATED(
|
|
void dump() const,
|
|
"only for use within the debugger");
|
|
|
|
/// Dump the requirement source.
|
|
void dump(llvm::raw_ostream &out, SourceManager *SrcMgr,
|
|
unsigned indent) const;
|
|
|
|
LLVM_ATTRIBUTE_DEPRECATED(
|
|
void print() const,
|
|
"only for use within the debugger");
|
|
|
|
/// Print the requirement source (shorter form)
|
|
void print(llvm::raw_ostream &out, SourceManager *SrcMgr) const;
|
|
};
|
|
|
|
/// A requirement source that potentially lacks a root \c PotentialArchetype.
|
|
/// The root will be supplied as soon as the appropriate dependent type is
|
|
/// resolved.
|
|
class GenericSignatureBuilder::FloatingRequirementSource {
|
|
enum Kind {
|
|
/// A fully-resolved requirement source, which does not need a root.
|
|
Resolved,
|
|
/// An explicit requirement source lacking a root.
|
|
Explicit,
|
|
/// An inferred requirement source lacking a root.
|
|
Inferred,
|
|
/// A requirement source augmented by an abstract protocol requirement
|
|
AbstractProtocol,
|
|
} kind;
|
|
|
|
using Storage =
|
|
llvm::PointerUnion3<const RequirementSource *, const TypeRepr *,
|
|
const RequirementRepr *>;
|
|
|
|
Storage storage;
|
|
|
|
// Additional storage for an abstract protocol requirement.
|
|
struct {
|
|
ProtocolDecl *protocol = nullptr;
|
|
WrittenRequirementLoc written;
|
|
} protocolReq;
|
|
|
|
FloatingRequirementSource(Kind kind, Storage storage)
|
|
: kind(kind), storage(storage) { }
|
|
|
|
public:
|
|
/// Implicit conversion from a resolved requirement source.
|
|
FloatingRequirementSource(const RequirementSource *source)
|
|
: FloatingRequirementSource(Resolved, source) { }
|
|
|
|
static FloatingRequirementSource forAbstract() {
|
|
return { Explicit, Storage() };
|
|
}
|
|
|
|
static FloatingRequirementSource forExplicit(const TypeRepr *typeRepr) {
|
|
return { Explicit, typeRepr };
|
|
}
|
|
|
|
static FloatingRequirementSource forExplicit(
|
|
const RequirementRepr *requirementRepr) {
|
|
return { Explicit, requirementRepr };
|
|
}
|
|
|
|
static FloatingRequirementSource forInferred(const TypeRepr *typeRepr) {
|
|
return { Inferred, typeRepr };
|
|
}
|
|
|
|
static FloatingRequirementSource viaProtocolRequirement(
|
|
const RequirementSource *base,
|
|
ProtocolDecl *inProtocol) {
|
|
FloatingRequirementSource result{ AbstractProtocol, base };
|
|
result.protocolReq.protocol = inProtocol;
|
|
return result;
|
|
}
|
|
|
|
static FloatingRequirementSource viaProtocolRequirement(
|
|
const RequirementSource *base,
|
|
ProtocolDecl *inProtocol,
|
|
WrittenRequirementLoc written) {
|
|
FloatingRequirementSource result{ AbstractProtocol, base };
|
|
result.protocolReq.protocol = inProtocol;
|
|
result.protocolReq.written = written;
|
|
return result;
|
|
}
|
|
|
|
/// Retrieve the complete requirement source rooted at the given potential
|
|
/// archetype.
|
|
const RequirementSource *getSource(PotentialArchetype *pa,
|
|
Type dependentType) const;
|
|
|
|
/// Retrieve the source location for this requirement.
|
|
SourceLoc getLoc() const;
|
|
};
|
|
|
|
class GenericSignatureBuilder::PotentialArchetype {
|
|
/// The parent of this potential archetype (for a nested type) or the
|
|
/// generic signature builder in which this root resides.
|
|
llvm::PointerUnion<PotentialArchetype*, GenericSignatureBuilder*> parentOrBuilder;
|
|
|
|
/// The identifier describing this particular archetype.
|
|
///
|
|
/// \c parentOrBuilder determines whether we have a nested type vs. a root,
|
|
/// while `isUnresolvedNestedType` determines whether we have an unresolved
|
|
/// nested type (vs. a resolved one);
|
|
union PAIdentifier {
|
|
/// The name of an unresolved, nested type.
|
|
Identifier name;
|
|
|
|
/// The associated type or typealias for a resolved nested type.
|
|
TypeDecl *assocTypeOrAlias;
|
|
|
|
/// The generic parameter key for a root.
|
|
GenericParamKey genericParam;
|
|
|
|
PAIdentifier(Identifier name) : name(name) { }
|
|
|
|
PAIdentifier(AssociatedTypeDecl *assocType)
|
|
: assocTypeOrAlias(assocType) { }
|
|
|
|
PAIdentifier(TypeAliasDecl *typeAlias)
|
|
: assocTypeOrAlias(typeAlias) { }
|
|
|
|
PAIdentifier(GenericParamKey genericParam) : genericParam(genericParam) { }
|
|
} identifier;
|
|
|
|
/// \brief The representative of the equivalence class of potential archetypes
|
|
/// to which this potential archetype belongs, or (for the representative)
|
|
/// the equivalence class itself.
|
|
mutable llvm::PointerUnion<PotentialArchetype *, EquivalenceClass *>
|
|
representativeOrEquivClass;
|
|
|
|
/// A stored nested type.
|
|
struct StoredNestedType {
|
|
/// The potential archetypes describing this nested type, all of which
|
|
/// are equivalent.
|
|
llvm::TinyPtrVector<PotentialArchetype *> archetypes;
|
|
|
|
typedef llvm::TinyPtrVector<PotentialArchetype *>::iterator iterator;
|
|
iterator begin() { return archetypes.begin(); }
|
|
iterator end() { return archetypes.end(); }
|
|
|
|
typedef llvm::TinyPtrVector<PotentialArchetype *>::const_iterator
|
|
const_iterator;
|
|
const_iterator begin() const { return archetypes.begin(); }
|
|
const_iterator end() const { return archetypes.end(); }
|
|
|
|
PotentialArchetype *front() const { return archetypes.front(); }
|
|
PotentialArchetype *back() const { return archetypes.back(); }
|
|
|
|
unsigned size() const { return archetypes.size(); }
|
|
bool empty() const { return archetypes.empty(); }
|
|
|
|
void push_back(PotentialArchetype *pa) {
|
|
archetypes.push_back(pa);
|
|
}
|
|
};
|
|
|
|
/// \brief The set of nested types of this archetype.
|
|
///
|
|
/// For a given nested type name, there may be multiple potential archetypes
|
|
/// corresponding to different associated types (from different protocols)
|
|
/// that share a name.
|
|
llvm::MapVector<Identifier, StoredNestedType> NestedTypes;
|
|
|
|
/// Tracks the number of conformances that
|
|
unsigned numConformancesInNestedType = 0;
|
|
|
|
/// Whether this is an unresolved nested type.
|
|
unsigned isUnresolvedNestedType : 1;
|
|
|
|
/// \brief Recursively conforms to itself.
|
|
unsigned IsRecursive : 1;
|
|
|
|
/// Whether this potential archetype is invalid, e.g., because it could not
|
|
/// be resolved.
|
|
unsigned Invalid : 1;
|
|
|
|
/// Whether we have detected recursion during the substitution of
|
|
/// the concrete type.
|
|
unsigned RecursiveConcreteType : 1;
|
|
|
|
/// Whether we have detected recursion during the substitution of
|
|
/// the superclass type.
|
|
unsigned RecursiveSuperclassType : 1;
|
|
|
|
/// Whether we have diagnosed a rename.
|
|
unsigned DiagnosedRename : 1;
|
|
|
|
/// If we have renamed this (nested) type due to typo correction,
|
|
/// the old name.
|
|
Identifier OrigName;
|
|
|
|
/// \brief Construct a new potential archetype for an unresolved
|
|
/// associated type.
|
|
PotentialArchetype(PotentialArchetype *parent, Identifier name)
|
|
: parentOrBuilder(parent), identifier(name), isUnresolvedNestedType(true),
|
|
IsRecursive(false), Invalid(false),
|
|
RecursiveConcreteType(false), RecursiveSuperclassType(false),
|
|
DiagnosedRename(false)
|
|
{
|
|
assert(parent != nullptr && "Not an associated type?");
|
|
}
|
|
|
|
/// \brief Construct a new potential archetype for an associated type.
|
|
PotentialArchetype(PotentialArchetype *parent, AssociatedTypeDecl *assocType)
|
|
: parentOrBuilder(parent), identifier(assocType),
|
|
isUnresolvedNestedType(false), IsRecursive(false), Invalid(false),
|
|
RecursiveConcreteType(false),
|
|
RecursiveSuperclassType(false), DiagnosedRename(false)
|
|
{
|
|
assert(parent != nullptr && "Not an associated type?");
|
|
}
|
|
|
|
/// \brief Construct a new potential archetype for a type alias.
|
|
PotentialArchetype(PotentialArchetype *parent, TypeAliasDecl *typeAlias)
|
|
: parentOrBuilder(parent), identifier(typeAlias),
|
|
isUnresolvedNestedType(false),
|
|
IsRecursive(false), Invalid(false),
|
|
RecursiveConcreteType(false),
|
|
RecursiveSuperclassType(false), DiagnosedRename(false)
|
|
{
|
|
assert(parent != nullptr && "Not an associated type?");
|
|
}
|
|
|
|
/// \brief Construct a new potential archetype for a generic parameter.
|
|
PotentialArchetype(GenericSignatureBuilder *builder, GenericParamKey genericParam)
|
|
: parentOrBuilder(builder), identifier(genericParam),
|
|
isUnresolvedNestedType(false),
|
|
IsRecursive(false), Invalid(false),
|
|
RecursiveConcreteType(false), RecursiveSuperclassType(false),
|
|
DiagnosedRename(false)
|
|
{
|
|
}
|
|
|
|
/// \brief Retrieve the representative for this archetype, performing
|
|
/// path compression on the way.
|
|
PotentialArchetype *getRepresentative() const;
|
|
|
|
/// Retrieve the generic signature builder with which this archetype is
|
|
/// associated.
|
|
GenericSignatureBuilder *getBuilder() const {
|
|
const PotentialArchetype *pa = this;
|
|
while (auto parent = pa->getParent())
|
|
pa = parent;
|
|
return pa->parentOrBuilder.get<GenericSignatureBuilder *>();
|
|
}
|
|
|
|
friend class GenericSignatureBuilder;
|
|
friend class GenericSignature;
|
|
|
|
/// \brief Retrieve the debug name of this potential archetype.
|
|
std::string getDebugName() const;
|
|
|
|
public:
|
|
~PotentialArchetype();
|
|
|
|
/// Retrieve the parent of this potential archetype, which will be non-null
|
|
/// when this potential archetype is an associated type.
|
|
PotentialArchetype *getParent() const {
|
|
return parentOrBuilder.dyn_cast<PotentialArchetype *>();
|
|
}
|
|
|
|
/// Retrieve the associated type to which this potential archetype
|
|
/// has been resolved.
|
|
AssociatedTypeDecl *getResolvedAssociatedType() const {
|
|
assert(getParent() && "Not an associated type");
|
|
if (isUnresolvedNestedType)
|
|
return nullptr;
|
|
|
|
return dyn_cast<AssociatedTypeDecl>(identifier.assocTypeOrAlias);
|
|
}
|
|
|
|
/// Resolve the potential archetype to the given associated type.
|
|
void resolveAssociatedType(AssociatedTypeDecl *assocType,
|
|
GenericSignatureBuilder &builder);
|
|
|
|
/// Resolve the potential archetype to the given typealias.
|
|
void resolveTypeAlias(TypeAliasDecl *typealias,
|
|
GenericSignatureBuilder &builder);
|
|
|
|
/// Determine whether this is a generic parameter.
|
|
bool isGenericParam() const {
|
|
return parentOrBuilder.is<GenericSignatureBuilder *>();
|
|
}
|
|
|
|
/// Retrieve the generic parameter key for a potential archetype that
|
|
/// represents this potential archetype.
|
|
///
|
|
/// \pre \c isGenericParam()
|
|
GenericParamKey getGenericParamKey() const {
|
|
assert(isGenericParam() && "Not a generic parameter");
|
|
return identifier.genericParam;
|
|
}
|
|
|
|
/// Retrieve the generic parameter key for the generic parameter at the
|
|
/// root of this potential archetype.
|
|
GenericParamKey getRootGenericParamKey() const {
|
|
if (auto parent = getParent())
|
|
return parent->getRootGenericParamKey();
|
|
|
|
return getGenericParamKey();
|
|
}
|
|
|
|
/// Retrieve the name of a nested potential archetype.
|
|
Identifier getNestedName() const {
|
|
assert(getParent() && "Not a nested type");
|
|
if (isUnresolvedNestedType)
|
|
return identifier.name;
|
|
|
|
return identifier.assocTypeOrAlias->getName();
|
|
}
|
|
|
|
/// Retrieve the type alias.
|
|
TypeAliasDecl *getTypeAliasDecl() const {
|
|
assert(getParent() && "not a nested type");
|
|
if (isUnresolvedNestedType)
|
|
return nullptr;
|
|
|
|
return dyn_cast<TypeAliasDecl>(identifier.assocTypeOrAlias);
|
|
}
|
|
|
|
/// Retrieve the set of protocols to which this potential archetype
|
|
/// conforms.
|
|
SmallVector<ProtocolDecl *, 4> getConformsTo() const {
|
|
SmallVector<ProtocolDecl *, 4> result;
|
|
|
|
if (auto equiv = getEquivalenceClassIfPresent()) {
|
|
for (const auto &entry : equiv->conformsTo)
|
|
result.push_back(entry.first);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Add a conformance to this potential archetype.
|
|
///
|
|
/// \returns true if the conformance was new, false if it already existed.
|
|
bool addConformance(ProtocolDecl *proto,
|
|
const RequirementSource *source,
|
|
GenericSignatureBuilder &builder);
|
|
|
|
/// Retrieve the superclass of this archetype.
|
|
Type getSuperclass() const {
|
|
if (auto equiv = getEquivalenceClassIfPresent())
|
|
return equiv->superclass;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
/// Retrieve the layout constraint of this archetype.
|
|
LayoutConstraint getLayout() const {
|
|
if (auto equivClass = getEquivalenceClassIfPresent())
|
|
return equivClass->layout;
|
|
|
|
return LayoutConstraint();
|
|
}
|
|
|
|
/// Retrieve the set of nested types.
|
|
const llvm::MapVector<Identifier, StoredNestedType> &getNestedTypes() const {
|
|
return NestedTypes;
|
|
}
|
|
|
|
/// \brief Determine the nesting depth of this potential archetype, e.g.,
|
|
/// the number of associated type references.
|
|
unsigned getNestingDepth() const;
|
|
|
|
/// Retrieve the equivalence class, if it's already present.
|
|
///
|
|
/// Otherwise, return null.
|
|
EquivalenceClass *getEquivalenceClassIfPresent() const {
|
|
return getRepresentative()->representativeOrEquivClass
|
|
.dyn_cast<EquivalenceClass *>();
|
|
}
|
|
|
|
/// Retrieve or create the equivalence class.
|
|
EquivalenceClass *getOrCreateEquivalenceClass() const;
|
|
|
|
/// Retrieve the equivalence class containing this potential archetype.
|
|
TinyPtrVector<PotentialArchetype *> getEquivalenceClassMembers() const {
|
|
if (auto equivClass = getEquivalenceClassIfPresent())
|
|
return equivClass->members;
|
|
|
|
return TinyPtrVector<PotentialArchetype *>(
|
|
const_cast<PotentialArchetype *>(this));
|
|
}
|
|
|
|
/// \brief Retrieve the potential archetype to be used as the anchor for
|
|
/// potential archetype computations.
|
|
PotentialArchetype *getArchetypeAnchor(GenericSignatureBuilder &builder);
|
|
|
|
/// Add a same-type constraint between this archetype and the given
|
|
/// other archetype.
|
|
void addSameTypeConstraint(PotentialArchetype *otherPA,
|
|
const RequirementSource *source);
|
|
|
|
/// Retrieve the same-type constraints.
|
|
ArrayRef<Constraint<PotentialArchetype *>> getSameTypeConstraints() const {
|
|
if (auto equivClass = getEquivalenceClassIfPresent()) {
|
|
auto known = equivClass->sameTypeConstraints.find(
|
|
const_cast<PotentialArchetype *>(this));
|
|
if (known == equivClass->sameTypeConstraints.end()) return { };
|
|
return known->second;
|
|
}
|
|
|
|
return { };
|
|
}
|
|
|
|
/// \brief Retrieve (or create) a nested type with the given name.
|
|
PotentialArchetype *getNestedType(Identifier Name,
|
|
GenericSignatureBuilder &builder);
|
|
|
|
/// \brief Retrieve (or create) a nested type with a known associated type.
|
|
PotentialArchetype *getNestedType(AssociatedTypeDecl *assocType,
|
|
GenericSignatureBuilder &builder);
|
|
|
|
/// \brief Retrieve (or create) a nested type with a known typealias.
|
|
PotentialArchetype *getNestedType(TypeAliasDecl *typealias,
|
|
GenericSignatureBuilder &builder);
|
|
|
|
/// \brief Retrieve (or create) a nested type that is the current best
|
|
/// nested archetype anchor (locally) with the given name.
|
|
///
|
|
/// When called on the archetype anchor, this will produce the named
|
|
/// archetype anchor.
|
|
PotentialArchetype *getNestedArchetypeAnchor(
|
|
Identifier name,
|
|
GenericSignatureBuilder &builder);
|
|
|
|
/// Describes the kind of update that is performed.
|
|
enum class NestedTypeUpdate {
|
|
/// Resolve an existing potential archetype, but don't create a new
|
|
/// one if not present.
|
|
ResolveExisting,
|
|
/// If this potential archetype is missing, create it.
|
|
AddIfMissing,
|
|
/// If this potential archetype is missing and would be a better anchor,
|
|
/// create it.
|
|
AddIfBetterAnchor,
|
|
};
|
|
|
|
/// Update the named nested type when we know this type conforms to the given
|
|
/// protocol.
|
|
///
|
|
/// \returns the potential archetype associated with the associated
|
|
/// type or typealias of the given protocol, unless the \c kind implies that
|
|
/// a potential archetype should not be created if it's missing.
|
|
PotentialArchetype *updateNestedTypeForConformance(
|
|
PointerUnion<AssociatedTypeDecl *, TypeAliasDecl *> type,
|
|
NestedTypeUpdate kind);
|
|
|
|
/// Update the named nested type when we know this type conforms to the given
|
|
/// protocol.
|
|
///
|
|
/// \returns the potential archetype associated with either an associated
|
|
/// type or typealias of the given protocol, unless the \c kind implies that
|
|
/// a potential archetype should not be created if it's missing.
|
|
PotentialArchetype *updateNestedTypeForConformance(
|
|
Identifier name,
|
|
ProtocolDecl *protocol,
|
|
NestedTypeUpdate kind);
|
|
|
|
/// \brief Retrieve (or build) the type corresponding to the potential
|
|
/// archetype within the given generic environment.
|
|
Type getTypeInContext(GenericSignatureBuilder &builder,
|
|
GenericEnvironment *genericEnv);
|
|
|
|
/// Retrieve the dependent type that describes this potential
|
|
/// archetype.
|
|
///
|
|
/// \param genericParams The set of generic parameters to use in the resulting
|
|
/// dependent type.
|
|
///
|
|
/// \param allowUnresolved If true, allow the result to contain
|
|
/// \c DependentMemberType types with a name but no specific associated
|
|
/// type.
|
|
Type getDependentType(ArrayRef<GenericTypeParamType *> genericParams,
|
|
bool allowUnresolved);
|
|
|
|
/// True if the potential archetype has been bound by a concrete type
|
|
/// constraint.
|
|
bool isConcreteType() const {
|
|
if (auto equivClass = getEquivalenceClassIfPresent())
|
|
return static_cast<bool>(equivClass->concreteType);
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Get the concrete type this potential archetype is constrained to.
|
|
Type getConcreteType() const {
|
|
if (auto equivClass = getEquivalenceClassIfPresent())
|
|
return equivClass->concreteType;
|
|
|
|
return Type();
|
|
}
|
|
|
|
void setIsRecursive() { IsRecursive = true; }
|
|
bool isRecursive() const { return IsRecursive; }
|
|
|
|
bool isInvalid() const { return Invalid; }
|
|
|
|
void setInvalid() { Invalid = true; }
|
|
|
|
/// Determine whether this archetype was renamed due to typo
|
|
/// correction. If so, \c getName() retrieves the new name.
|
|
bool wasRenamed() const { return !OrigName.empty(); }
|
|
|
|
/// Note that this potential archetype was is going to be renamed (due to typo
|
|
/// correction), saving the old name.
|
|
void saveNameForRenaming() {
|
|
OrigName = getNestedName();
|
|
}
|
|
|
|
/// For a renamed potential archetype, retrieve the original name.
|
|
Identifier getOriginalName() const {
|
|
assert(wasRenamed());
|
|
return OrigName;
|
|
}
|
|
|
|
/// Whether we already diagnosed this rename.
|
|
bool alreadyDiagnosedRename() const { return DiagnosedRename; }
|
|
|
|
/// Note that we already diagnosed this rename.
|
|
void setAlreadyDiagnosedRename() { DiagnosedRename = true; }
|
|
|
|
LLVM_ATTRIBUTE_DEPRECATED(
|
|
void dump() const,
|
|
"only for use within the debugger");
|
|
|
|
void dump(llvm::raw_ostream &Out, SourceManager *SrcMgr,
|
|
unsigned Indent) const;
|
|
|
|
friend class GenericSignatureBuilder;
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|