1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
//===--- OpenedExistentials.h - Utilities for existential types -*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_OPENED_EXISTENTIALS_H
#define SWIFT_OPENED_EXISTENTIALS_H
#include "swift/AST/Type.h"
#include "swift/Basic/OptionalEnum.h"
#include <optional>
namespace swift {
class CanGenericSignature;
class GenericTypeParamType;
/// Describes the least favorable positions at which a requirement refers
/// to a given generic parameter in terms of variance, for use in the
/// is-inheritable and is-available-existential checks.
class GenericParameterReferenceInfo final {
using OptionalTypePosition = OptionalEnum<decltype(TypePosition::Covariant)>;
public:
/// Whether the uncurried interface type of the declaration, stripped of any
/// optionality, is a direct reference to the generic parameter at hand. For
/// example, "func foo(x: Int) -> () -> Self?" has a covariant 'Self' result.
bool hasCovariantSelfResult;
OptionalTypePosition selfRef;
OptionalTypePosition assocTypeRef;
/// A reference to 'Self'.
static GenericParameterReferenceInfo forSelfRef(TypePosition position) {
return GenericParameterReferenceInfo(false, position, std::nullopt);
}
/// A reference to the generic parameter in covariant result position.
static GenericParameterReferenceInfo forCovariantResult() {
return GenericParameterReferenceInfo(true, TypePosition::Covariant,
std::nullopt);
}
/// A reference to 'Self' through an associated type.
static GenericParameterReferenceInfo forAssocTypeRef(TypePosition position) {
return GenericParameterReferenceInfo(false, std::nullopt, position);
}
GenericParameterReferenceInfo &operator|=(const GenericParameterReferenceInfo &other);
explicit operator bool() const {
return hasCovariantSelfResult || selfRef || assocTypeRef;
}
GenericParameterReferenceInfo()
: hasCovariantSelfResult(false), selfRef(std::nullopt),
assocTypeRef(std::nullopt) {}
private:
GenericParameterReferenceInfo(bool hasCovariantSelfResult, OptionalTypePosition selfRef,
OptionalTypePosition assocTypeRef)
: hasCovariantSelfResult(hasCovariantSelfResult), selfRef(selfRef),
assocTypeRef(assocTypeRef) {}
};
/// Find references to the given generic parameter in the type signature of the
/// given declaration using the given generic signature.
///
/// \param skipParamIndex If the value is a function or subscript declaration,
/// specifies the index of the parameter that shall be skipped.
GenericParameterReferenceInfo
findGenericParameterReferences(const ValueDecl *value, CanGenericSignature sig,
GenericTypeParamType *origParam,
GenericTypeParamType *openedParam,
std::optional<unsigned> skipParamIndex);
/// Find references to 'Self' in the type signature of this declaration.
GenericParameterReferenceInfo findExistentialSelfReferences(const ValueDecl *value);
/// Determine whether referencing the given member on the
/// given existential base type is supported. This is the case only if the
/// type of the member, spelled in the context of \p baseTy, does not contain
/// 'Self' or 'Self'-rooted dependent member types in non-covariant position.
bool isMemberAvailableOnExistential(Type baseTy,
const ValueDecl *member);
/// Flags that should be applied to the existential argument type after
/// opening.
enum class OpenedExistentialAdjustmentFlags {
/// The argument should be made inout after opening.
InOut = 0x01,
LValue = 0x02,
};
using OpenedExistentialAdjustments =
OptionSet<OpenedExistentialAdjustmentFlags>;
/// Determine whether we should open up the existential argument to the
/// given parameters.
///
/// \param callee The function or subscript being called.
/// \param paramIdx The index specifying which function parameter is being
/// initialized.
/// \param paramTy The type of the parameter as it was opened in the constraint
/// system.
/// \param argTy The type of the argument.
///
/// \returns If the argument type is existential and opening it can bind a
/// generic parameter in the callee, returns the generic parameter, type
/// variable (from the opened parameter type) the existential type that needs
/// to be opened (from the argument type), and the adjustments that need to be
/// applied to the existential type after it is opened.
std::optional<std::tuple<GenericTypeParamType *, TypeVariableType *,
Type, OpenedExistentialAdjustments>>
canOpenExistentialCallArgument(ValueDecl *callee, unsigned paramIdx,
Type paramTy, Type argTy);
/// Given a type that includes an existential type that has been opened to
/// the given type variable, replace the opened type variable and its member
/// types with their upper bounds.
Type typeEraseOpenedExistentialReference(Type type, Type existentialBaseType,
TypeVariableType *openedTypeVar,
TypePosition outermostPosition);
/// Given a type that includes opened existential archetypes derived from
/// the given generic environment, replace the archetypes with their upper
/// bounds.
Type typeEraseOpenedArchetypesFromEnvironment(Type type,
GenericEnvironment *env);
} // end namespace swift
#endif
|