Skip to content

Commit c7fd60f

Browse files
Merge pull request #39492 from AnthonyLatsis/se-309-2
SE-309: Covariant erasure for dependent member types
2 parents b4926df + 6a25198 commit c7fd60f

37 files changed

+2544
-962
lines changed

include/swift/AST/Decl.h

Lines changed: 49 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,6 +2157,45 @@ class PoundDiagnosticDecl : public Decl {
21572157

21582158
class OpaqueTypeDecl;
21592159

2160+
/// Describes the least favorable positions at which a requirement refers
2161+
/// to 'Self' in terms of variance, for use in the is-inheritable and
2162+
/// is-available-existential checks.
2163+
class SelfReferenceInfo final {
2164+
using OptionalTypePosition = OptionalEnum<decltype(TypePosition::Covariant)>;
2165+
2166+
public:
2167+
bool hasCovariantSelfResult;
2168+
2169+
OptionalTypePosition selfRef;
2170+
OptionalTypePosition assocTypeRef;
2171+
2172+
/// A reference to 'Self'.
2173+
static SelfReferenceInfo forSelfRef(TypePosition position) {
2174+
return SelfReferenceInfo(false, position, llvm::None);
2175+
}
2176+
2177+
/// A reference to 'Self' through an associated type.
2178+
static SelfReferenceInfo forAssocTypeRef(TypePosition position) {
2179+
return SelfReferenceInfo(false, llvm::None, position);
2180+
}
2181+
2182+
SelfReferenceInfo &operator|=(const SelfReferenceInfo &other);
2183+
2184+
explicit operator bool() const {
2185+
return hasCovariantSelfResult || selfRef || assocTypeRef;
2186+
}
2187+
2188+
SelfReferenceInfo()
2189+
: hasCovariantSelfResult(false), selfRef(llvm::None),
2190+
assocTypeRef(llvm::None) {}
2191+
2192+
private:
2193+
SelfReferenceInfo(bool hasCovariantSelfResult, OptionalTypePosition selfRef,
2194+
OptionalTypePosition assocTypeRef)
2195+
: hasCovariantSelfResult(hasCovariantSelfResult), selfRef(selfRef),
2196+
assocTypeRef(assocTypeRef) {}
2197+
};
2198+
21602199
/// ValueDecl - All named decls that are values in the language. These can
21612200
/// have a type, etc.
21622201
class ValueDecl : public Decl {
@@ -2634,6 +2673,16 @@ class ValueDecl : public Decl {
26342673
/// @_dynamicReplacement(for: ...), compute the original declaration
26352674
/// that this declaration dynamically replaces.
26362675
ValueDecl *getDynamicallyReplacedDecl() const;
2676+
2677+
/// Report 'Self' references within the type of this declaration as a
2678+
/// member of the given existential base type.
2679+
///
2680+
/// \param treatNonResultCovariantSelfAsInvariant If true, 'Self' or 'Self?'
2681+
/// is considered covariant only when it appears as the immediate type of a
2682+
/// property, or the uncurried result type of a method/subscript, e.g.
2683+
/// '() -> () -> Self'.
2684+
SelfReferenceInfo findExistentialSelfReferences(
2685+
Type baseTy, bool treatNonResultCovariantSelfAsInvariant) const;
26372686
};
26382687

26392688
/// This is a common base class for declarations which declare a type.
@@ -4212,82 +4261,6 @@ class ClassDecl final : public NominalTypeDecl {
42124261
bool isForeignReferenceType();
42134262
};
42144263

4215-
/// A convenience wrapper around the \c SelfReferencePosition::Kind enum.
4216-
struct SelfReferencePosition final {
4217-
enum Kind : uint8_t { None, Covariant, Contravariant, Invariant };
4218-
4219-
private:
4220-
Kind kind;
4221-
4222-
public:
4223-
SelfReferencePosition(Kind kind) : kind(kind) {}
4224-
4225-
SelfReferencePosition flipped() const {
4226-
switch (kind) {
4227-
case None:
4228-
case Invariant:
4229-
return *this;
4230-
case Covariant:
4231-
return Contravariant;
4232-
case Contravariant:
4233-
return Covariant;
4234-
}
4235-
llvm_unreachable("unhandled self reference position!");
4236-
}
4237-
4238-
explicit operator bool() const { return kind > None; }
4239-
4240-
operator Kind() const { return kind; }
4241-
};
4242-
4243-
/// Describes the least favorable positions at which a requirement refers
4244-
/// to 'Self' in terms of variance, for use in the is-inheritable and
4245-
/// is-available-existential checks.
4246-
struct SelfReferenceInfo final {
4247-
using Position = SelfReferencePosition;
4248-
4249-
bool hasCovariantSelfResult;
4250-
Position selfRef;
4251-
Position assocTypeRef;
4252-
4253-
/// A reference to 'Self'.
4254-
static SelfReferenceInfo forSelfRef(Position position) {
4255-
assert(position);
4256-
return SelfReferenceInfo(false, position, Position::None);
4257-
}
4258-
4259-
/// A reference to 'Self' through an associated type.
4260-
static SelfReferenceInfo forAssocTypeRef(Position position) {
4261-
assert(position);
4262-
return SelfReferenceInfo(false, Position::None, position);
4263-
}
4264-
4265-
SelfReferenceInfo operator|=(const SelfReferenceInfo &pos) {
4266-
hasCovariantSelfResult |= pos.hasCovariantSelfResult;
4267-
if (pos.selfRef > selfRef) {
4268-
selfRef = pos.selfRef;
4269-
}
4270-
if (pos.assocTypeRef > assocTypeRef) {
4271-
assocTypeRef = pos.assocTypeRef;
4272-
}
4273-
return *this;
4274-
}
4275-
4276-
explicit operator bool() const {
4277-
return hasCovariantSelfResult || selfRef || assocTypeRef;
4278-
}
4279-
4280-
SelfReferenceInfo()
4281-
: hasCovariantSelfResult(false), selfRef(Position::None),
4282-
assocTypeRef(Position::None) {}
4283-
4284-
private:
4285-
SelfReferenceInfo(bool hasCovariantSelfResult, Position selfRef,
4286-
Position assocTypeRef)
4287-
: hasCovariantSelfResult(hasCovariantSelfResult), selfRef(selfRef),
4288-
assocTypeRef(assocTypeRef) {}
4289-
};
4290-
42914264
/// The set of known protocols for which derived conformances are supported.
42924265
enum class KnownDerivableProtocolKind : uint8_t {
42934266
RawRepresentable,
@@ -4481,21 +4454,6 @@ class ProtocolDecl final : public NominalTypeDecl {
44814454
/// Does this protocol require a self-conformance witness table?
44824455
bool requiresSelfConformanceWitnessTable() const;
44834456

4484-
/// Find direct Self references within the given requirement.
4485-
///
4486-
/// \param treatNonResultCovariantSelfAsInvariant If true, 'Self' is only
4487-
/// assumed to be covariant in a top-level non-function type, or in the
4488-
/// eventual result type of a top-level function type.
4489-
SelfReferenceInfo
4490-
findProtocolSelfReferences(const ValueDecl *decl,
4491-
bool treatNonResultCovariantSelfAsInvariant) const;
4492-
4493-
/// Determine whether we are allowed to refer to an existential type
4494-
/// conforming to this protocol. This is only permitted if the type of
4495-
/// the member does not contain any associated types, and does not
4496-
/// contain 'Self' in 'parameter' or 'other' position.
4497-
bool isAvailableInExistential(const ValueDecl *decl) const;
4498-
44994457
/// Determine whether an existential type must be explicitly prefixed
45004458
/// with \c any. \c any is required if any of the members contain
45014459
/// an associated type, or if \c Self appears in non-covariant position.

include/swift/AST/GenericSignature.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
390390

391391
bool isCanonicalTypeInContext(Type type) const;
392392

393+
/// Determine whether the given type parameter is defined under this generic
394+
/// signature.
393395
bool isValidTypeInContext(Type type) const;
394396

395397
/// Retrieve the conformance access path used to extract the conformance of
@@ -428,6 +430,13 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
428430
/// generic parameter types by their sugared form.
429431
Type getSugaredType(Type type) const;
430432

433+
/// Given a type parameter, compute the most specific supertype (upper bound)
434+
/// that is not dependent on other type parameters.
435+
///
436+
/// \note If the upper bound is a protocol or protocol composition,
437+
/// will return an instance of \c ExistentialType.
438+
Type getNonDependentUpperBounds(Type type) const;
439+
431440
static void Profile(llvm::FoldingSetNodeID &ID,
432441
TypeArrayView<GenericTypeParamType> genericParams,
433442
ArrayRef<Requirement> requirements);

include/swift/AST/Type.h

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,34 @@ enum class ForeignRepresentableKind : uint8_t {
203203
StaticBridged,
204204
};
205205

206+
/// An enum wrapper used to describe the variance position of a type within
207+
/// another type. For example, a function type is covariant in its result type;
208+
/// therefore, the result type is in covariant position relative to the function
209+
/// type.
210+
struct TypePosition final {
211+
enum : uint8_t { Covariant, Contravariant, Invariant };
212+
213+
private:
214+
decltype(Covariant) kind;
215+
216+
public:
217+
TypePosition(decltype(kind) kind) : kind(kind) {}
218+
219+
TypePosition flipped() const {
220+
switch (kind) {
221+
case Invariant:
222+
return *this;
223+
case Covariant:
224+
return Contravariant;
225+
case Contravariant:
226+
return Covariant;
227+
}
228+
llvm_unreachable("Unhandled type position!");
229+
}
230+
231+
operator decltype(kind)() const { return kind; }
232+
};
233+
206234
/// Type - This is a simple value object that contains a pointer to a type
207235
/// class. This is potentially sugared. We use this throughout the codebase
208236
/// instead of a raw "TypeBase*" to disable equality comparison, which is unsafe
@@ -241,47 +269,47 @@ class Type {
241269
/// its children.
242270
bool findIf(llvm::function_ref<bool(Type)> pred) const;
243271

244-
/// Transform the given type by applying the user-provided function to
245-
/// each type.
272+
/// Transform the given type by recursively applying the user-provided
273+
/// function to each node.
246274
///
247-
/// This routine applies the given function to transform one type into
248-
/// another. If the function leaves the type unchanged, recurse into the
249-
/// child type nodes and transform those. If any child type node changes,
250-
/// the parent type node will be rebuilt.
251-
///
252-
/// If at any time the function returns a null type, the null will be
253-
/// propagated out.
254-
///
255-
/// \param fn A function object with the signature \c Type(Type), which
256-
/// accepts a type and returns either a transformed type or a null type.
275+
/// \param fn A function object with the signature \c Type(Type) , which
276+
/// accepts a type and returns either a transformed type or a null type
277+
/// (which will propagate out the null type).
257278
///
258279
/// \returns the result of transforming the type.
259280
Type transform(llvm::function_ref<Type(Type)> fn) const;
260281

261-
/// Transform the given type by applying the user-provided function to
262-
/// each type.
263-
///
264-
/// This routine applies the given function to transform one type into
265-
/// another. If the function leaves the type unchanged, recurse into the
266-
/// child type nodes and transform those. If any child type node changes,
267-
/// the parent type node will be rebuilt.
268-
///
269-
/// If at any time the function returns a null type, the null will be
270-
/// propagated out.
282+
/// Transform the given type by recursively applying the user-provided
283+
/// function to each node.
271284
///
272285
/// If the function returns \c None, the transform operation will
273286
///
274-
/// \param fn A function object with the signature
275-
/// \c Optional<Type>(TypeBase *), which accepts a type pointer and returns a
276-
/// transformed type, a null type (which will propagate the null type to the
277-
/// outermost \c transform() call), or None (to indicate that the transform
278-
/// operation should recursively transform the subtypes). The function object
279-
/// should use \c dyn_cast rather \c getAs, because the transform itself
280-
/// handles desugaring.
287+
/// \param fn A function object which accepts a type pointer and returns a
288+
/// transformed type, a null type (which will propagate out the null type),
289+
/// or None (to indicate that the transform operation should recursively
290+
/// transform the children). The function object should use \c dyn_cast rather
291+
/// than \c getAs when the transform is intended to preserve sugar
281292
///
282293
/// \returns the result of transforming the type.
283294
Type transformRec(llvm::function_ref<Optional<Type>(TypeBase *)> fn) const;
284295

296+
/// Transform the given type by recursively applying the user-provided
297+
/// function to each node.
298+
///
299+
/// \param pos The variance position of the receiver.
300+
///
301+
/// \param fn A function object which accepts a type pointer along with its
302+
/// variance position and returns either a transformed type, a null type
303+
/// (which will propagate out the null type), or \c None (to indicate that the
304+
/// transform operation should recursively transform the children).
305+
/// The function object should use \c dyn_cast rather than \c getAs when the
306+
/// transform is intended to preserve sugar.
307+
///
308+
/// \returns the result of transforming the type.
309+
Type transformWithPosition(
310+
TypePosition pos,
311+
llvm::function_ref<Optional<Type>(TypeBase *, TypePosition)> fn) const;
312+
285313
/// Look through the given type and its children and apply fn to them.
286314
void visit(llvm::function_ref<void (Type)> fn) const {
287315
findIf([&fn](Type t) -> bool {

include/swift/AST/Types.h

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -513,13 +513,13 @@ class alignas(1 << TypeAlignInBits) TypeBase
513513
TypeBase *getWithoutSyntaxSugar();
514514

515515
/// getASTContext - Return the ASTContext that this type belongs to.
516-
ASTContext &getASTContext();
517-
516+
ASTContext &getASTContext() const;
517+
518518
/// isEqual - Return true if these two types are equal, ignoring sugar.
519519
///
520520
/// To compare sugar, check for pointer equality of the underlying TypeBase *
521521
/// values, obtained by calling getPointer().
522-
bool isEqual(Type Other);
522+
bool isEqual(Type Other) const;
523523

524524
/// getDesugaredType - If this type is a sugared type, remove all levels of
525525
/// sugar until we get down to a non-sugar type.
@@ -621,7 +621,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
621621

622622
/// Determine whether the type involves the given opened existential
623623
/// archetype.
624-
bool hasOpenedExistential(OpenedArchetypeType *opened);
624+
bool hasOpenedExistentialWithRoot(const OpenedArchetypeType *root) const;
625625

626626
/// Determine whether the type involves an opaque type.
627627
bool hasOpaqueArchetype() const {
@@ -637,13 +637,13 @@ class alignas(1 << TypeAlignInBits) TypeBase
637637
/// Determine whether the type is an opened existential type with Error inside
638638
bool isOpenedExistentialWithError();
639639

640-
/// Retrieve the set of opened existential archetypes that occur
641-
/// within this type.
642-
void getOpenedExistentials(SmallVectorImpl<OpenedArchetypeType *> &opened);
640+
/// Retrieve the set of root opened archetypes that occur within this type.
641+
void getRootOpenedExistentials(
642+
SmallVectorImpl<OpenedArchetypeType *> &rootOpenedArchetypes) const;
643643

644-
/// Erase the given opened existential type by replacing it with its
645-
/// existential type throughout the given type.
646-
Type eraseOpenedExistential(OpenedArchetypeType *opened);
644+
/// Replace opened archetypes with the given root with their most
645+
/// specific non-dependent upper bounds throughout this type.
646+
Type typeEraseOpenedArchetypesWithRoot(const OpenedArchetypeType *root) const;
647647

648648
/// Given a declaration context, returns a function type with the 'self'
649649
/// type curried as the input if the declaration context describes a type.
@@ -5536,7 +5536,8 @@ class ArchetypeType : public SubstitutableType,
55365536
/// primary archetype.
55375537
ArchetypeType *getParent() const;
55385538

5539-
/// Return the root archetype parent of this archetype.
5539+
/// Return the archetype that represents the root generic parameter of its
5540+
/// interface type.
55405541
ArchetypeType *getRoot() const;
55415542

55425543
/// Determine whether this is a root archetype within the environment.
@@ -5773,6 +5774,12 @@ class OpenedArchetypeType final : public ArchetypeType,
57735774
/// Retrieve the opened existential type
57745775
Type getOpenedExistentialType() const;
57755776

5777+
/// Return the archetype that represents the root generic parameter of its
5778+
/// interface type.
5779+
OpenedArchetypeType *getRoot() const {
5780+
return cast<OpenedArchetypeType>(ArchetypeType::getRoot());
5781+
}
5782+
57765783
static bool classof(const TypeBase *T) {
57775784
return T->getKind() == TypeKind::OpenedArchetype;
57785785
}
@@ -6287,7 +6294,7 @@ BEGIN_CAN_TYPE_WRAPPER(PackExpansionType, Type)
62876294
END_CAN_TYPE_WRAPPER(PackExpansionType, Type)
62886295

62896296
/// getASTContext - Return the ASTContext that this type belongs to.
6290-
inline ASTContext &TypeBase::getASTContext() {
6297+
inline ASTContext &TypeBase::getASTContext() const {
62916298
// If this type is canonical, it has the ASTContext in it.
62926299
if (isCanonical())
62936300
return *const_cast<ASTContext*>(Context);

0 commit comments

Comments
 (0)