//===--- PropertyMap.h - Properties of type parameter terms 0000-*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2021 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // A description of this data structure and its purpose can be found in // PropertyMap.cpp. // //===----------------------------------------------------------------------===// #ifndef SWIFT_PROPERTYMAP_H #define SWIFT_PROPERTYMAP_H #include "swift/AST/LayoutConstraint.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include #include #include "Debug.h" #include "RewriteContext.h" #include "RewriteSystem.h" namespace llvm { class raw_ostream; } namespace swift { class ProtocolConformance; class ProtocolDecl; enum class RequirementKind : unsigned; namespace rewriting { class MutableTerm; class Term; /// Records superclass requirements at a given level in the class hierarchy. struct SuperclassRequirement { /// The most specific superclass constraint (in type difference order) for /// this level in the class hierarchy. std::optional SuperclassType; /// Superclass rules that apply to this key. llvm::SmallVector, 1> SuperclassRules; }; /// Stores a convenient representation of all "property-like" rewrite rules of /// the form T.[p] => T, where [p] is a property symbol, for some term 'T'. class PropertyBag { friend class PropertyMap; /// The fully reduced term whose properties are recorded in this property bag. Term Key; /// All protocols this type conforms to. llvm::TinyPtrVector ConformsTo; /// The corresponding protocol conformance rules. llvm::SmallVector ConformsToRules; /// The most specific layout constraint this type satisfies. LayoutConstraint Layout; /// The corresponding layout rule for the above. std::optional LayoutRule; /// The most specific superclass declaration for which this type has a /// superclass constraint. const ClassDecl *SuperclassDecl = nullptr; /// Used for unifying superclass rules at different levels in the class /// hierarchy. For each class declaration, stores a symbol and rule pair /// for the most specific substituted type. llvm::SmallDenseMap Superclasses; /// The most specific concrete type constraint this type satisfies. std::optional ConcreteType; /// Concrete type rules that apply to this key. llvm::SmallVector, 1> ConcreteTypeRules; /// Cache of associated type declarations. llvm::SmallDenseMap AssocTypes; explicit PropertyBag(Term key) : Key(key) {} void copyPropertiesFrom(const PropertyBag *next, RewriteContext &ctx); PropertyBag(const PropertyBag &) = delete; PropertyBag(PropertyBag &&) = delete; PropertyBag &operator=(const PropertyBag &) = delete; PropertyBag &operator=(PropertyBag &&) = delete; const SuperclassRequirement &getSuperclassRequirement() const { ASSERT(SuperclassDecl != nullptr); auto found = Superclasses.find(SuperclassDecl); ASSERT(found != Superclasses.end()); return found->second; } MutableTerm getPrefixAfterStrippingKey(const MutableTerm &lookupTerm) const; public: Term getKey() const { return Key; } void dump(llvm::raw_ostream &out) const; bool hasSuperclassBound() const { return SuperclassDecl != nullptr; } CanType getSuperclassBound() const { return getSuperclassRequirement().SuperclassType->getConcreteType(); } Type getSuperclassBound( ArrayRef genericParams, const MutableTerm &lookupTerm, const PropertyMap &map) const; bool isConcreteType() const { return ConcreteType.has_value(); } CanType getConcreteType() const { return ConcreteType->getConcreteType(); } Type getConcreteType( ArrayRef genericParams, const MutableTerm &lookupTerm, const PropertyMap &map) const; LayoutConstraint getLayoutConstraint() const { return Layout; } ArrayRef getConformsTo() const { return ConformsTo; } AssociatedTypeDecl *getAssociatedType(Identifier name); Symbol concretelySimplifySubstitution(const MutableTerm &mutTerm, RewriteContext &ctx, RewritePath *path) const; void verify(const RewriteSystem &system) const; }; /// Stores all rewrite rules of the form T.[p] => T, where [p] is a property /// symbol, for all terms 'T'. /// /// Out-of-line methods are documented in PropertyMap.cpp. class PropertyMap { RewriteContext &Context; RewriteSystem &System; std::vector Entries; Trie Trie; // Building the property map introduces new induced rules, which // runs another round of Knuth-Bendix completion, which rebuilds the // property map again. // // To avoid wasted work from re-introducing the same induced rules, // we track the rules we've seen already on previous builds. /// Superclass requirements always imply a layout requirement, and /// concrete type requirements where the type is a class imply a /// superclass requirement. /// /// Keep track of such rules to avoid wasted work from recording the /// same rewrite loop more than once. llvm::DenseSet CheckedRules; /// When a type parameter is subject to two requirements of the same /// kind, we have a pair of rewrite rules T.[p1] => T and T.[p2] => T. /// /// One of these rules might imply the other. Keep track of these pairs /// to avoid wasted work from recording the same rewrite loop more than /// once. llvm::DenseSet> CheckedRulePairs; DebugOptions Debug; PropertyBag *getOrCreateProperties(Term key); PropertyMap(const PropertyMap &) = delete; PropertyMap(PropertyMap &&) = delete; PropertyMap &operator=(const PropertyMap &) = delete; PropertyMap &operator=(PropertyMap &&) = delete; public: explicit PropertyMap(RewriteSystem &system) : Context(system.getRewriteContext()), System(system) { Debug = Context.getDebugOptions(); } ~PropertyMap(); PropertyBag *lookUpProperties(std::reverse_iterator begin, std::reverse_iterator end) const; PropertyBag *lookUpProperties(const MutableTerm &key) const; void buildPropertyMap(); void dump(llvm::raw_ostream &out) const; /// Return the rewrite context used for allocating memory. RewriteContext &getRewriteContext() const { return Context; } ////////////////////////////////////////////////////////////////////////////// /// /// Term to type conversion. The opposite direction is implemented in /// RewriteContext because it does not depend on the current rewrite system. /// ////////////////////////////////////////////////////////////////////////////// Type getTypeForTerm(Term term, ArrayRef genericParams) const; Type getTypeForTerm(const MutableTerm &term, ArrayRef genericParams) const; Type getTypeFromSubstitutionSchema( Type schema, ArrayRef substitutions, ArrayRef genericParams, const MutableTerm &prefix) const; private: void clear(); bool checkRuleOnce(unsigned ruleID); bool checkRulePairOnce(unsigned firstRuleID, unsigned secondRuleID); void addProperty(Term key, Symbol property, unsigned ruleID); void addConformanceProperty(Term key, Symbol property, unsigned ruleID); void addLayoutProperty(Term key, Symbol property, unsigned ruleID); void unifyConcreteTypes(Term key, Symbol lhsProperty, unsigned lhsRuleID, Symbol rhsProperty, unsigned rhsRuleID); void unifyConcreteTypes( Term key, std::optional &bestProperty, llvm::SmallVectorImpl> &existingRules, Symbol property, unsigned ruleID); void recordSuperclassRelation(Term key, Symbol superclassType, unsigned superclassRuleID, const ClassDecl *otherClass); void addSuperclassProperty(Term key, Symbol property, unsigned ruleID); void addConcreteTypeProperty(Term key, Symbol property, unsigned ruleID); void checkConcreteTypeRequirements(); void concretizeNestedTypesFromConcreteParents(); void concretizeNestedTypesFromConcreteParent( Term key, RequirementKind requirementKind, unsigned concreteRuleID, CanType concreteType, ArrayRef substitutions, ArrayRef conformsToRules, ArrayRef conformsTo); void concretizeTypeWitnessInConformance( Term key, RequirementKind requirementKind, Symbol concreteConformanceSymbol, ProtocolConformanceRef conformance, AssociatedTypeDecl *assocType) const; void inferConditionalRequirements( ProtocolConformance *concrete, ArrayRef substitutions) const; MutableTerm computeConstraintTermForTypeWitness( Term key, RequirementKind requirementKind, CanType concreteType, CanType typeWitness, const MutableTerm &subjectType, ArrayRef substitutions, RewritePath &path) const; void recordConcreteConformanceRule( unsigned concreteRuleID, unsigned conformanceRuleID, RequirementKind requirementKind, Symbol concreteConformanceSymbol) const; void verify() const; }; } // end namespace rewriting } // end namespace swift #endif