mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Sema: Move constructor synthesis code from TypeCheckDecl.cpp to CodeSynthesis.cpp
This was split between the two files; consolidate it in CodeSynthesis.cpp.
This commit is contained in:
@@ -18,16 +18,17 @@
|
||||
|
||||
#include "ConstraintSystem.h"
|
||||
#include "TypeChecker.h"
|
||||
#include "TypeCheckDecl.h"
|
||||
#include "TypeCheckObjC.h"
|
||||
#include "TypeCheckType.h"
|
||||
#include "swift/AST/ASTWalker.h"
|
||||
#include "swift/AST/ASTPrinter.h"
|
||||
#include "swift/AST/Availability.h"
|
||||
#include "swift/AST/Expr.h"
|
||||
#include "swift/AST/GenericEnvironment.h"
|
||||
#include "swift/AST/GenericSignatureBuilder.h"
|
||||
#include "swift/AST/Initializer.h"
|
||||
#include "swift/AST/ParameterList.h"
|
||||
#include "swift/AST/PropertyWrappers.h"
|
||||
#include "swift/AST/PrettyStackTrace.h"
|
||||
#include "swift/AST/ProtocolConformance.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
#include "swift/Basic/Defer.h"
|
||||
@@ -169,6 +170,18 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
|
||||
arg->setDefaultArgumentKind(DefaultArgumentKind::StoredProperty);
|
||||
}
|
||||
|
||||
/// Describes the kind of implicit constructor that will be
|
||||
/// generated.
|
||||
enum class ImplicitConstructorKind {
|
||||
/// The default constructor, which default-initializes each
|
||||
/// of the instance variables.
|
||||
Default,
|
||||
/// The memberwise constructor, which initializes each of
|
||||
/// the instance variables from a parameter of the same type and
|
||||
/// name.
|
||||
Memberwise
|
||||
};
|
||||
|
||||
/// Create an implicit struct or class constructor.
|
||||
///
|
||||
/// \param decl The struct or class for which a constructor will be created.
|
||||
@@ -176,12 +189,11 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
|
||||
///
|
||||
/// \returns The newly-created constructor, which has already been type-checked
|
||||
/// (but has not been added to the containing struct or class).
|
||||
ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
|
||||
NominalTypeDecl *decl,
|
||||
ImplicitConstructorKind ICK) {
|
||||
static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
|
||||
ImplicitConstructorKind ICK,
|
||||
ASTContext &ctx) {
|
||||
assert(!decl->hasClangNode());
|
||||
|
||||
ASTContext &ctx = tc.Context;
|
||||
SourceLoc Loc = decl->getLoc();
|
||||
auto accessLevel = AccessLevel::Internal;
|
||||
|
||||
@@ -201,7 +213,7 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
|
||||
|
||||
accessLevel = std::min(accessLevel, var->getFormalAccess());
|
||||
|
||||
tc.validateDecl(var);
|
||||
ctx.getLazyResolver()->resolveDeclSignature(var);
|
||||
auto varInterfaceType = var->getValueInterfaceType();
|
||||
|
||||
if (var->getAttrs().hasAttribute<LazyAttr>()) {
|
||||
@@ -444,12 +456,11 @@ configureGenericDesignatedInitOverride(ASTContext &ctx,
|
||||
}
|
||||
|
||||
static void
|
||||
configureInheritedDesignatedInitAttributes(TypeChecker &tc,
|
||||
ClassDecl *classDecl,
|
||||
configureInheritedDesignatedInitAttributes(ClassDecl *classDecl,
|
||||
ConstructorDecl *ctor,
|
||||
ConstructorDecl *superclassCtor) {
|
||||
ConstructorDecl *superclassCtor,
|
||||
ASTContext &ctx) {
|
||||
assert(ctor->getDeclContext() == classDecl);
|
||||
auto &ctx = tc.Context;
|
||||
|
||||
AccessLevel access = classDecl->getFormalAccess();
|
||||
access = std::max(access, AccessLevel::Internal);
|
||||
@@ -579,13 +590,35 @@ synthesizeDesignatedInitOverride(AbstractFunctionDecl *fn, void *context) {
|
||||
/*isTypeChecked=*/true };
|
||||
}
|
||||
|
||||
ConstructorDecl *
|
||||
swift::createDesignatedInitOverride(TypeChecker &tc,
|
||||
ClassDecl *classDecl,
|
||||
ConstructorDecl *superclassCtor,
|
||||
DesignatedInitKind kind) {
|
||||
auto &ctx = tc.Context;
|
||||
/// The kind of designated initializer to synthesize.
|
||||
enum class DesignatedInitKind {
|
||||
/// A stub initializer, which is not visible to name lookup and
|
||||
/// merely aborts at runtime.
|
||||
Stub,
|
||||
|
||||
/// An initializer that simply chains to the corresponding
|
||||
/// superclass initializer.
|
||||
Chaining
|
||||
};
|
||||
|
||||
/// Create a new initializer that overrides the given designated
|
||||
/// initializer.
|
||||
///
|
||||
/// \param classDecl The subclass in which the new initializer will
|
||||
/// be declared.
|
||||
///
|
||||
/// \param superclassCtor The superclass initializer for which this
|
||||
/// routine will create an override.
|
||||
///
|
||||
/// \param kind The kind of initializer to synthesize.
|
||||
///
|
||||
/// \returns the newly-created initializer that overrides \p
|
||||
/// superclassCtor.
|
||||
static ConstructorDecl *
|
||||
createDesignatedInitOverride(ClassDecl *classDecl,
|
||||
ConstructorDecl *superclassCtor,
|
||||
DesignatedInitKind kind,
|
||||
ASTContext &ctx) {
|
||||
// Lookup will sometimes give us initializers that are from the ancestors of
|
||||
// our immediate superclass. So, from the superclass constructor, we look
|
||||
// one level up to the enclosing type context which will either be a class
|
||||
@@ -655,8 +688,8 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
|
||||
|
||||
ctor->setValidationToChecked();
|
||||
|
||||
configureInheritedDesignatedInitAttributes(tc, classDecl, ctor,
|
||||
superclassCtor);
|
||||
configureInheritedDesignatedInitAttributes(classDecl, ctor,
|
||||
superclassCtor, ctx);
|
||||
|
||||
if (kind == DesignatedInitKind::Stub) {
|
||||
// Make this a stub implementation.
|
||||
@@ -676,3 +709,532 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
|
||||
|
||||
return ctor;
|
||||
}
|
||||
|
||||
/// Diagnose a missing required initializer.
|
||||
static void diagnoseMissingRequiredInitializer(
|
||||
ClassDecl *classDecl,
|
||||
ConstructorDecl *superInitializer,
|
||||
ASTContext &ctx) {
|
||||
// Find the location at which we should insert the new initializer.
|
||||
SourceLoc insertionLoc;
|
||||
SourceLoc indentationLoc;
|
||||
for (auto member : classDecl->getMembers()) {
|
||||
// If we don't have an indentation location yet, grab one from this
|
||||
// member.
|
||||
if (indentationLoc.isInvalid()) {
|
||||
indentationLoc = member->getLoc();
|
||||
}
|
||||
|
||||
// We only want to look at explicit constructors.
|
||||
auto ctor = dyn_cast<ConstructorDecl>(member);
|
||||
if (!ctor)
|
||||
continue;
|
||||
|
||||
if (ctor->isImplicit())
|
||||
continue;
|
||||
|
||||
insertionLoc = ctor->getEndLoc();
|
||||
indentationLoc = ctor->getLoc();
|
||||
}
|
||||
|
||||
// If no initializers were listed, start at the opening '{' for the class.
|
||||
if (insertionLoc.isInvalid()) {
|
||||
insertionLoc = classDecl->getBraces().Start;
|
||||
}
|
||||
if (indentationLoc.isInvalid()) {
|
||||
indentationLoc = classDecl->getBraces().End;
|
||||
}
|
||||
|
||||
// Adjust the insertion location to point at the end of this line (i.e.,
|
||||
// the start of the next line).
|
||||
insertionLoc = Lexer::getLocForEndOfLine(ctx.SourceMgr,
|
||||
insertionLoc);
|
||||
|
||||
// Find the indentation used on the indentation line.
|
||||
StringRef extraIndentation;
|
||||
StringRef indentation = Lexer::getIndentationForLine(
|
||||
ctx.SourceMgr, indentationLoc, &extraIndentation);
|
||||
|
||||
// Pretty-print the superclass initializer into a string.
|
||||
// FIXME: Form a new initializer by performing the appropriate
|
||||
// substitutions of subclass types into the superclass types, so that
|
||||
// we get the right generic parameters.
|
||||
std::string initializerText;
|
||||
{
|
||||
PrintOptions options;
|
||||
options.PrintImplicitAttrs = false;
|
||||
|
||||
// Render the text.
|
||||
llvm::raw_string_ostream out(initializerText);
|
||||
{
|
||||
ExtraIndentStreamPrinter printer(out, indentation);
|
||||
printer.printNewline();
|
||||
|
||||
// If there is no explicit 'required', print one.
|
||||
bool hasExplicitRequiredAttr = false;
|
||||
if (auto requiredAttr
|
||||
= superInitializer->getAttrs().getAttribute<RequiredAttr>())
|
||||
hasExplicitRequiredAttr = !requiredAttr->isImplicit();
|
||||
|
||||
if (!hasExplicitRequiredAttr)
|
||||
printer << "required ";
|
||||
|
||||
superInitializer->print(printer, options);
|
||||
}
|
||||
|
||||
// Add a dummy body.
|
||||
out << " {\n";
|
||||
out << indentation << extraIndentation << "fatalError(\"";
|
||||
superInitializer->getFullName().printPretty(out);
|
||||
out << " has not been implemented\")\n";
|
||||
out << indentation << "}\n";
|
||||
}
|
||||
|
||||
// Complain.
|
||||
ctx.Diags.diagnose(insertionLoc, diag::required_initializer_missing,
|
||||
superInitializer->getFullName(),
|
||||
superInitializer->getDeclContext()->getDeclaredInterfaceType())
|
||||
.fixItInsert(insertionLoc, initializerText);
|
||||
|
||||
ctx.Diags.diagnose(findNonImplicitRequiredInit(superInitializer),
|
||||
diag::required_initializer_here);
|
||||
}
|
||||
|
||||
void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
|
||||
// We can only synthesize implicit constructors for classes and structs.
|
||||
if (!isa<ClassDecl>(decl) && !isa<StructDecl>(decl))
|
||||
return;
|
||||
|
||||
// If we already added implicit initializers, we're done.
|
||||
if (decl->addedImplicitInitializers())
|
||||
return;
|
||||
|
||||
// Don't add implicit constructors for an invalid declaration
|
||||
if (decl->isInvalid())
|
||||
return;
|
||||
|
||||
// Don't add implicit constructors in parseable interfaces.
|
||||
if (auto *SF = decl->getParentSourceFile()) {
|
||||
if (SF->Kind == SourceFileKind::Interface) {
|
||||
decl->setAddedImplicitInitializers();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Bail out if we're validating one of our constructors or stored properties
|
||||
// already; we'll revisit the issue later.
|
||||
if (isa<ClassDecl>(decl)) {
|
||||
for (auto member : decl->getMembers()) {
|
||||
if (auto ctor = dyn_cast<ConstructorDecl>(member)) {
|
||||
validateDecl(ctor);
|
||||
if (!ctor->hasValidSignature())
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isa<StructDecl>(decl)) {
|
||||
for (auto member : decl->getMembers()) {
|
||||
if (auto var = dyn_cast<VarDecl>(member)) {
|
||||
if (!var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true))
|
||||
continue;
|
||||
|
||||
validateDecl(var);
|
||||
if (!var->hasValidSignature())
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decl->setAddedImplicitInitializers();
|
||||
|
||||
// Check whether there is a user-declared constructor or an instance
|
||||
// variable.
|
||||
bool FoundMemberwiseInitializedProperty = false;
|
||||
bool SuppressDefaultInitializer = false;
|
||||
bool FoundDesignatedInit = false;
|
||||
|
||||
SmallVector<std::pair<ValueDecl *, Type>, 4> declaredInitializers;
|
||||
llvm::SmallPtrSet<ConstructorDecl *, 4> overriddenInits;
|
||||
if (decl->hasClangNode() && isa<ClassDecl>(decl)) {
|
||||
// Objective-C classes may have interesting initializers in extensions.
|
||||
for (auto member : decl->lookupDirect(DeclBaseName::createConstructor())) {
|
||||
auto ctor = dyn_cast<ConstructorDecl>(member);
|
||||
if (!ctor)
|
||||
continue;
|
||||
|
||||
// Swift initializers added in extensions of Objective-C classes can never
|
||||
// be overrides.
|
||||
if (!ctor->hasClangNode())
|
||||
continue;
|
||||
|
||||
if (auto overridden = ctor->getOverriddenDecl())
|
||||
overriddenInits.insert(overridden);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (auto member : decl->getMembers()) {
|
||||
if (auto ctor = dyn_cast<ConstructorDecl>(member)) {
|
||||
// Initializers that were synthesized to fulfill derived conformances
|
||||
// should not prevent default initializer synthesis.
|
||||
if (ctor->isDesignatedInit() && !ctor->isSynthesized())
|
||||
FoundDesignatedInit = true;
|
||||
|
||||
if (isa<StructDecl>(decl))
|
||||
continue;
|
||||
|
||||
if (!ctor->isInvalid()) {
|
||||
auto type = getMemberTypeForComparison(Context, ctor, nullptr);
|
||||
declaredInitializers.push_back({ctor, type});
|
||||
}
|
||||
|
||||
if (auto overridden = ctor->getOverriddenDecl())
|
||||
overriddenInits.insert(overridden);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto var = dyn_cast<VarDecl>(member)) {
|
||||
// If this is a backing storage property for a property wrapper,
|
||||
// skip it.
|
||||
if (var->getOriginalWrappedProperty())
|
||||
continue;
|
||||
|
||||
if (var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) {
|
||||
// Initialized 'let' properties have storage, but don't get an argument
|
||||
// to the memberwise initializer since they already have an initial
|
||||
// value that cannot be overridden.
|
||||
if (var->isLet() && var->isParentInitialized()) {
|
||||
|
||||
// We cannot handle properties like:
|
||||
// let (a,b) = (1,2)
|
||||
// for now, just disable implicit init synthesization in structs in
|
||||
// this case.
|
||||
auto SP = var->getParentPattern();
|
||||
if (auto *TP = dyn_cast<TypedPattern>(SP))
|
||||
SP = TP->getSubPattern();
|
||||
if (!isa<NamedPattern>(SP) && isa<StructDecl>(decl))
|
||||
return;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
FoundMemberwiseInitializedProperty = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// If a stored property lacks an initial value and if there is no way to
|
||||
// synthesize an initial value (e.g. for an optional) then we suppress
|
||||
// generation of the default initializer.
|
||||
if (auto pbd = dyn_cast<PatternBindingDecl>(member)) {
|
||||
if (pbd->hasStorage() && !pbd->isStatic()) {
|
||||
for (auto entry : pbd->getPatternList()) {
|
||||
if (entry.isInitialized()) continue;
|
||||
|
||||
// If one of the bound variables is @NSManaged, go ahead no matter
|
||||
// what.
|
||||
bool CheckDefaultInitializer = true;
|
||||
entry.getPattern()->forEachVariable([&](VarDecl *vd) {
|
||||
if (vd->getAttrs().hasAttribute<NSManagedAttr>())
|
||||
CheckDefaultInitializer = false;
|
||||
});
|
||||
|
||||
// If we cannot default initialize the property, we cannot
|
||||
// synthesize a default initializer for the class.
|
||||
if (CheckDefaultInitializer && !pbd->isDefaultInitializable())
|
||||
SuppressDefaultInitializer = true;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auto structDecl = dyn_cast<StructDecl>(decl)) {
|
||||
assert(!structDecl->hasUnreferenceableStorage() &&
|
||||
"User-defined structs cannot have unreferenceable storage");
|
||||
|
||||
if (!FoundDesignatedInit) {
|
||||
// For a struct with memberwise initialized properties, we add a
|
||||
// memberwise init.
|
||||
if (FoundMemberwiseInitializedProperty) {
|
||||
// Create the implicit memberwise constructor.
|
||||
auto ctor = createImplicitConstructor(
|
||||
decl,
|
||||
ImplicitConstructorKind::Memberwise,
|
||||
Context);
|
||||
decl->addMember(ctor);
|
||||
}
|
||||
|
||||
// If we found a stored property, add a default constructor.
|
||||
if (!SuppressDefaultInitializer)
|
||||
defineDefaultConstructor(decl);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// For a class with a superclass, automatically define overrides
|
||||
// for all of the superclass's designated initializers.
|
||||
// FIXME: Currently skipping generic classes.
|
||||
auto classDecl = cast<ClassDecl>(decl);
|
||||
if (Type superclassTy = classDecl->getSuperclass()) {
|
||||
bool canInheritInitializers = (!SuppressDefaultInitializer &&
|
||||
!FoundDesignatedInit);
|
||||
|
||||
// We can't define these overrides if we have any uninitialized
|
||||
// stored properties.
|
||||
if (SuppressDefaultInitializer && !FoundDesignatedInit &&
|
||||
!classDecl->hasClangNode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *superclassDecl = superclassTy->getClassOrBoundGenericClass();
|
||||
assert(superclassDecl && "Superclass of class is not a class?");
|
||||
if (!superclassDecl->addedImplicitInitializers())
|
||||
addImplicitConstructors(superclassDecl);
|
||||
|
||||
auto ctors = lookupConstructors(classDecl, superclassTy,
|
||||
NameLookupFlags::IgnoreAccessControl);
|
||||
|
||||
bool canInheritConvenienceInitalizers =
|
||||
!superclassDecl->hasMissingDesignatedInitializers();
|
||||
SmallVector<ConstructorDecl *, 4> requiredConvenienceInitializers;
|
||||
for (auto memberResult : ctors) {
|
||||
auto member = memberResult.getValueDecl();
|
||||
|
||||
// Skip unavailable superclass initializers.
|
||||
if (AvailableAttr::isUnavailable(member))
|
||||
continue;
|
||||
|
||||
// Skip invalid superclass initializers.
|
||||
auto superclassCtor = dyn_cast<ConstructorDecl>(member);
|
||||
if (superclassCtor->isInvalid())
|
||||
continue;
|
||||
|
||||
// If we have an override for this constructor, it's okay.
|
||||
if (overriddenInits.count(superclassCtor) > 0)
|
||||
continue;
|
||||
|
||||
// We only care about required or designated initializers.
|
||||
if (!superclassCtor->isDesignatedInit()) {
|
||||
if (superclassCtor->isRequired()) {
|
||||
assert(superclassCtor->isInheritable() &&
|
||||
"factory initializers cannot be 'required'");
|
||||
requiredConvenienceInitializers.push_back(superclassCtor);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, it may no longer be safe to inherit convenience
|
||||
// initializers.
|
||||
canInheritConvenienceInitalizers &= canInheritInitializers;
|
||||
|
||||
// Everything after this is only relevant for Swift classes being defined.
|
||||
if (classDecl->hasClangNode())
|
||||
continue;
|
||||
|
||||
// If the superclass initializer is not accessible from the derived
|
||||
// class, don't synthesize an override, since we cannot reference the
|
||||
// superclass initializer's method descriptor at all.
|
||||
//
|
||||
// FIXME: This should be checked earlier as part of calculating
|
||||
// canInheritInitializers.
|
||||
if (!superclassCtor->isAccessibleFrom(classDecl))
|
||||
continue;
|
||||
|
||||
// Diagnose a missing override of a required initializer.
|
||||
if (superclassCtor->isRequired() && !canInheritInitializers) {
|
||||
diagnoseMissingRequiredInitializer(classDecl, superclassCtor, Context);
|
||||
continue;
|
||||
}
|
||||
|
||||
// A designated or required initializer has not been overridden.
|
||||
|
||||
bool alreadyDeclared = false;
|
||||
for (const auto &ctorAndType : declaredInitializers) {
|
||||
auto *ctor = ctorAndType.first;
|
||||
auto type = ctorAndType.second;
|
||||
auto parentType = getMemberTypeForComparison(
|
||||
Context, superclassCtor, ctor);
|
||||
|
||||
if (isOverrideBasedOnType(ctor, type, superclassCtor, parentType)) {
|
||||
alreadyDeclared = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have already introduced an initializer with this parameter type,
|
||||
// don't add one now.
|
||||
if (alreadyDeclared)
|
||||
continue;
|
||||
|
||||
// If we're inheriting initializers, create an override delegating
|
||||
// to 'super.init'. Otherwise, create a stub which traps at runtime.
|
||||
auto kind = canInheritInitializers
|
||||
? DesignatedInitKind::Chaining
|
||||
: DesignatedInitKind::Stub;
|
||||
|
||||
// We have a designated initializer. Create an override of it.
|
||||
// FIXME: Validation makes sure we get a generic signature here.
|
||||
validateDecl(classDecl);
|
||||
if (auto ctor = createDesignatedInitOverride(
|
||||
classDecl, superclassCtor, kind, Context)) {
|
||||
classDecl->addMember(ctor);
|
||||
}
|
||||
}
|
||||
|
||||
if (canInheritConvenienceInitalizers) {
|
||||
classDecl->setInheritsSuperclassInitializers();
|
||||
} else {
|
||||
for (ConstructorDecl *requiredCtor : requiredConvenienceInitializers)
|
||||
diagnoseMissingRequiredInitializer(classDecl, requiredCtor, Context);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FoundDesignatedInit) {
|
||||
// For a class with no superclass, automatically define a default
|
||||
// constructor.
|
||||
|
||||
// ... unless there are uninitialized stored properties.
|
||||
if (SuppressDefaultInitializer)
|
||||
return;
|
||||
|
||||
defineDefaultConstructor(decl);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker::synthesizeMemberForLookup(NominalTypeDecl *target,
|
||||
DeclName member) {
|
||||
auto baseName = member.getBaseName();
|
||||
|
||||
// Checks whether the target conforms to the given protocol. If the
|
||||
// conformance is incomplete, force the conformance.
|
||||
//
|
||||
// Returns whether the target conforms to the protocol.
|
||||
auto evaluateTargetConformanceTo = [&](ProtocolDecl *protocol) {
|
||||
if (!protocol)
|
||||
return false;
|
||||
|
||||
auto targetType = target->getDeclaredInterfaceType();
|
||||
if (auto ref = conformsToProtocol(
|
||||
targetType, protocol, target,
|
||||
ConformanceCheckFlags::SkipConditionalRequirements)) {
|
||||
if (auto *conformance = dyn_cast<NormalProtocolConformance>(
|
||||
ref->getConcrete()->getRootConformance())) {
|
||||
if (conformance->getState() == ProtocolConformanceState::Incomplete) {
|
||||
checkConformance(conformance);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if (member.isSimpleName() && !baseName.isSpecial()) {
|
||||
if (baseName.getIdentifier() == Context.Id_CodingKeys) {
|
||||
// CodingKeys is a special type which may be synthesized as part of
|
||||
// Encodable/Decodable conformance. If the target conforms to either
|
||||
// protocol and would derive conformance to either, the type may be
|
||||
// synthesized.
|
||||
// If the target conforms to either and the conformance has not yet been
|
||||
// evaluated, then we should do that here.
|
||||
//
|
||||
// Try to synthesize Decodable first. If that fails, try to synthesize
|
||||
// Encodable. If either succeeds and CodingKeys should have been
|
||||
// synthesized, it will be synthesized.
|
||||
auto *decodableProto = Context.getProtocol(KnownProtocolKind::Decodable);
|
||||
auto *encodableProto = Context.getProtocol(KnownProtocolKind::Encodable);
|
||||
if (!evaluateTargetConformanceTo(decodableProto))
|
||||
(void)evaluateTargetConformanceTo(encodableProto);
|
||||
}
|
||||
|
||||
if ((baseName.getIdentifier().str().startswith("$") ||
|
||||
baseName.getIdentifier().str().startswith("_")) &&
|
||||
baseName.getIdentifier().str().size() > 1) {
|
||||
// $- and _-prefixed variables can be generated by properties that have
|
||||
// attached property wrappers.
|
||||
auto originalPropertyName =
|
||||
Context.getIdentifier(baseName.getIdentifier().str().substr(1));
|
||||
for (auto member : target->lookupDirect(originalPropertyName)) {
|
||||
if (auto var = dyn_cast<VarDecl>(member)) {
|
||||
if (var->hasAttachedPropertyWrapper()) {
|
||||
auto sourceFile = var->getDeclContext()->getParentSourceFile();
|
||||
if (sourceFile && sourceFile->Kind != SourceFileKind::Interface)
|
||||
(void)var->getPropertyWrapperBackingPropertyInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
auto argumentNames = member.getArgumentNames();
|
||||
if (member.isCompoundName() && argumentNames.size() != 1)
|
||||
return;
|
||||
|
||||
if (baseName == DeclBaseName::createConstructor() &&
|
||||
(member.isSimpleName() || argumentNames.front() == Context.Id_from)) {
|
||||
// init(from:) may be synthesized as part of derived conformance to the
|
||||
// Decodable protocol.
|
||||
// If the target should conform to the Decodable protocol, check the
|
||||
// conformance here to attempt synthesis.
|
||||
auto *decodableProto = Context.getProtocol(KnownProtocolKind::Decodable);
|
||||
(void)evaluateTargetConformanceTo(decodableProto);
|
||||
} else if (!baseName.isSpecial() &&
|
||||
baseName.getIdentifier() == Context.Id_encode &&
|
||||
(member.isSimpleName() ||
|
||||
argumentNames.front() == Context.Id_to)) {
|
||||
// encode(to:) may be synthesized as part of derived conformance to the
|
||||
// Encodable protocol.
|
||||
// If the target should conform to the Encodable protocol, check the
|
||||
// conformance here to attempt synthesis.
|
||||
auto *encodableProto = Context.getProtocol(KnownProtocolKind::Encodable);
|
||||
(void)evaluateTargetConformanceTo(encodableProto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Synthesizer callback for a function body consisting of "return".
|
||||
static std::pair<BraceStmt *, bool>
|
||||
synthesizeSingleReturnFunctionBody(AbstractFunctionDecl *afd, void *) {
|
||||
ASTContext &ctx = afd->getASTContext();
|
||||
SmallVector<ASTNode, 1> stmts;
|
||||
stmts.push_back(new (ctx) ReturnStmt(afd->getLoc(), nullptr));
|
||||
return { BraceStmt::create(ctx, afd->getLoc(), stmts, afd->getLoc(), true),
|
||||
/*isTypeChecked=*/true };
|
||||
}
|
||||
|
||||
void TypeChecker::defineDefaultConstructor(NominalTypeDecl *decl) {
|
||||
FrontendStatsTracer StatsTracer(Context.Stats, "define-default-ctor", decl);
|
||||
PrettyStackTraceDecl stackTrace("defining default constructor for",
|
||||
decl);
|
||||
|
||||
// Clang-imported types should never get a default constructor, just a
|
||||
// memberwise one.
|
||||
if (decl->hasClangNode())
|
||||
return;
|
||||
|
||||
// A class is only default initializable if it's a root class.
|
||||
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
|
||||
// If the class has a superclass, we should have either inherited it's
|
||||
// designated initializers or diagnosed the absence of our own.
|
||||
if (classDecl->getSuperclass())
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the default constructor.
|
||||
auto ctor = createImplicitConstructor(decl,
|
||||
ImplicitConstructorKind::Default,
|
||||
Context);
|
||||
|
||||
// Add the constructor.
|
||||
decl->addMember(ctor);
|
||||
|
||||
// Lazily synthesize an empty body for the default constructor.
|
||||
ctor->setBodySynthesizer(synthesizeSingleReturnFunctionBody);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user