Rationalize Implicit Member Synthesis Somewhat

Codable's deep magic currently forces conformance checks in the middle
of name lookup in order to inject CodingKeys into lookup results.  This
is compounded by the fact that this lookup fixup is occuring
incrementally, meaning depending on order of requirements being looked
up, Decl::getMembers() will give you a different answer.

Compounding this, NameLookup relied on the LazyResolver to formalize
this layering violation, and relied on implicit laziness to guard
against re-entrancy.

The approach is multi-pronged:
1) Shift the layering violation into the request evaluator
2) Spell out the kinds of resolution we support explicitly (make them
easier to find and kill)
3) Remove the LazyResolver entrypoint this was relying on
4) Split off the property wrappers part into its own utility
This commit is contained in:
Robert Widmann
2019-11-04 17:56:02 -08:00
parent 34ad0eb83d
commit d4906ac10b
11 changed files with 188 additions and 82 deletions

View File

@@ -18,6 +18,7 @@
SWIFT_TYPEID(AncestryFlags)
SWIFT_TYPEID(CtorInitializerKind)
SWIFT_TYPEID(GenericSignature)
SWIFT_TYPEID(ImplicitMemberAction)
SWIFT_TYPEID(ParamSpecifier)
SWIFT_TYPEID(PropertyWrapperBackingPropertyInfo)
SWIFT_TYPEID(PropertyWrapperTypeInfo)

View File

@@ -55,6 +55,7 @@ class TypeAliasDecl;
class Type;
struct TypePair;
enum class AncestryFlags : uint8_t;
enum class ImplicitMemberAction : uint8_t;
// Define the AST type zone (zone 1)
#define SWIFT_TYPEID_ZONE AST

View File

@@ -477,13 +477,16 @@ protected:
IsDebuggerAlias : 1
);
SWIFT_INLINE_BITFIELD(NominalTypeDecl, GenericTypeDecl, 1+1,
SWIFT_INLINE_BITFIELD(NominalTypeDecl, GenericTypeDecl, 1+1+1,
/// Whether we have already added implicitly-defined initializers
/// to this declaration.
AddedImplicitInitializers : 1,
/// Whether there is are lazily-loaded conformances for this nominal type.
HasLazyConformances : 1
HasLazyConformances : 1,
/// Whether this nominal type is having its semantic members resolved.
IsComputingSemanticMembers : 1
);
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+2+1+1+8+16,
@@ -3328,6 +3331,7 @@ protected:
Bits.NominalTypeDecl.AddedImplicitInitializers = false;
ExtensionGeneration = 0;
Bits.NominalTypeDecl.HasLazyConformances = false;
Bits.NominalTypeDecl.IsComputingSemanticMembers = false;
}
friend class ProtocolType;
@@ -3475,6 +3479,8 @@ public:
/// declaration, or \c nullptr if it doesn't have one.
ConstructorDecl *getDefaultInitializer() const;
void synthesizeSemanticMembersIfNeeded(DeclName member);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() >= DeclKind::First_NominalTypeDecl &&

View File

@@ -52,9 +52,6 @@ public:
/// the given protocol conformance.
virtual void resolveWitness(const NormalProtocolConformance *conformance,
ValueDecl *requirement) = 0;
/// Resolve an implicitly-generated member with the given name.
virtual void resolveImplicitMember(NominalTypeDecl *nominal, DeclName member) = 0;
};
class LazyMemberLoader;

View File

@@ -1668,6 +1668,35 @@ public:
void cacheResult(bool value) const;
};
// The actions this request takes are all huge layering violations.
//
// Please do not add any more.
enum class ImplicitMemberAction : uint8_t {
ResolveImplicitInit,
ResolveCodingKeys,
ResolveEncodable,
ResolveDecodable,
};
class ResolveImplicitMemberRequest
: public SimpleRequest<ResolveImplicitMemberRequest,
bool(NominalTypeDecl *, ImplicitMemberAction),
CacheKind::Uncached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
llvm::Expected<bool> evaluate(Evaluator &evaluator, NominalTypeDecl *NTD,
ImplicitMemberAction action) const;
public:
// Separate caching.
bool isCached() const { return true; }
};
// Allow AnyValue to compare two Type values, even though Type doesn't
// support ==.
template<>
@@ -1689,6 +1718,7 @@ AnyValue::Holder<GenericSignature>::equals(const HolderBase &other) const {
void simple_display(llvm::raw_ostream &out, Type value);
void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);
void simple_display(llvm::raw_ostream &out, ImplicitMemberAction action);
#define SWIFT_TYPEID_ZONE TypeChecker
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"

View File

@@ -174,6 +174,9 @@ SWIFT_REQUEST(TypeChecker, HasUserDefinedDesignatedInitRequest,
bool(NominalTypeDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, HasMemberwiseInitRequest,
bool(StructDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
bool(NominalTypeDecl *, ImplicitMemberAction), Uncached,
NoLocationInfo)
SWIFT_REQUEST(TypeChecker, SynthesizeMemberwiseInitRequest,
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest,