blob: 2de600597475b96ab5a729ba6e5e88dea27d2b51 [file] [log] [blame]
//===--- TypeCheckDecl.cpp - Type Checking for Declarations ---------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for declarations.
//
//===----------------------------------------------------------------------===//
#include "CodeSynthesis.h"
#include "ConstraintSystem.h"
#include "DerivedConformances.h"
#include "TypeChecker.h"
#include "TypeCheckAccess.h"
#include "TypeCheckDecl.h"
#include "TypeCheckAvailability.h"
#include "TypeCheckObjC.h"
#include "TypeCheckType.h"
#include "MiscDiagnostics.h"
#include "swift/AST/AccessScope.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/Expr.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericSignatureBuilder.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/ReferencedNameTracker.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeWalker.h"
#include "swift/Basic/Statistic.h"
#include "swift/Parse/Lexer.h"
#include "swift/Parse/Parser.h"
#include "swift/Serialization/SerializedModuleLoader.h"
#include "swift/Strings.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Defer.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DJB.h"
using namespace swift;
#define DEBUG_TYPE "Serialization"
STATISTIC(NumLazyRequirementSignaturesLoaded,
"# of lazily-deserialized requirement signatures loaded");
#undef DEBUG_TYPE
#define DEBUG_TYPE "TypeCheckDecl"
namespace {
/// Used during enum raw value checking to identify duplicate raw values.
/// Character, string, float, and integer literals are all keyed by value.
/// Float and integer literals are additionally keyed by numeric equivalence.
struct RawValueKey {
enum class Kind : uint8_t {
String, Float, Int, Tombstone, Empty
} kind;
struct IntValueTy {
uint64_t v0;
uint64_t v1;
IntValueTy(const APInt &bits) {
APInt bits128 = bits.sextOrTrunc(128);
assert(bits128.getBitWidth() <= 128);
const uint64_t *data = bits128.getRawData();
v0 = data[0];
v1 = data[1];
}
};
struct FloatValueTy {
uint64_t v0;
uint64_t v1;
};
// FIXME: doesn't accommodate >64-bit or signed raw integer or float values.
union {
StringRef stringValue;
IntValueTy intValue;
FloatValueTy floatValue;
};
explicit RawValueKey(LiteralExpr *expr) {
switch (expr->getKind()) {
case ExprKind::IntegerLiteral:
kind = Kind::Int;
intValue = IntValueTy(cast<IntegerLiteralExpr>(expr)->getValue());
return;
case ExprKind::FloatLiteral: {
APFloat value = cast<FloatLiteralExpr>(expr)->getValue();
llvm::APSInt asInt(127, /*isUnsigned=*/false);
bool isExact = false;
APFloat::opStatus status =
value.convertToInteger(asInt, APFloat::rmTowardZero, &isExact);
if (asInt.getBitWidth() <= 128 && status == APFloat::opOK && isExact) {
kind = Kind::Int;
intValue = IntValueTy(asInt);
return;
}
APInt bits = value.bitcastToAPInt();
const uint64_t *data = bits.getRawData();
if (bits.getBitWidth() == 80) {
kind = Kind::Float;
floatValue = FloatValueTy{ data[0], data[1] };
} else {
assert(bits.getBitWidth() == 64);
kind = Kind::Float;
floatValue = FloatValueTy{ data[0], 0 };
}
return;
}
case ExprKind::StringLiteral:
kind = Kind::String;
stringValue = cast<StringLiteralExpr>(expr)->getValue();
return;
default:
llvm_unreachable("not a valid literal expr for raw value");
}
}
explicit RawValueKey(Kind k) : kind(k) {
assert((k == Kind::Tombstone || k == Kind::Empty)
&& "this ctor is only for creating DenseMap special values");
}
};
/// Used during enum raw value checking to identify the source of a raw value,
/// which may have been derived by auto-incrementing, for diagnostic purposes.
struct RawValueSource {
/// The decl that has the raw value.
EnumElementDecl *sourceElt;
/// If the sourceDecl didn't explicitly name a raw value, this is the most
/// recent preceding decl with an explicit raw value. This is used to
/// diagnose 'autoincrementing from' messages.
EnumElementDecl *lastExplicitValueElt;
};
} // end anonymous namespace
namespace llvm {
template<>
class DenseMapInfo<RawValueKey> {
public:
static RawValueKey getEmptyKey() {
return RawValueKey(RawValueKey::Kind::Empty);
}
static RawValueKey getTombstoneKey() {
return RawValueKey(RawValueKey::Kind::Tombstone);
}
static unsigned getHashValue(RawValueKey k) {
switch (k.kind) {
case RawValueKey::Kind::Float:
// Hash as bits. We want to treat distinct but IEEE-equal values as not
// equal.
return DenseMapInfo<uint64_t>::getHashValue(k.floatValue.v0) ^
DenseMapInfo<uint64_t>::getHashValue(k.floatValue.v1);
case RawValueKey::Kind::Int:
return DenseMapInfo<uint64_t>::getHashValue(k.intValue.v0) &
DenseMapInfo<uint64_t>::getHashValue(k.intValue.v1);
case RawValueKey::Kind::String:
return DenseMapInfo<StringRef>::getHashValue(k.stringValue);
case RawValueKey::Kind::Empty:
case RawValueKey::Kind::Tombstone:
return 0;
}
llvm_unreachable("Unhandled RawValueKey in switch.");
}
static bool isEqual(RawValueKey a, RawValueKey b) {
if (a.kind != b.kind)
return false;
switch (a.kind) {
case RawValueKey::Kind::Float:
// Hash as bits. We want to treat distinct but IEEE-equal values as not
// equal.
return a.floatValue.v0 == b.floatValue.v0 &&
a.floatValue.v1 == b.floatValue.v1;
case RawValueKey::Kind::Int:
return a.intValue.v0 == b.intValue.v0 &&
a.intValue.v1 == b.intValue.v1;
case RawValueKey::Kind::String:
return a.stringValue.equals(b.stringValue);
case RawValueKey::Kind::Empty:
case RawValueKey::Kind::Tombstone:
return true;
}
llvm_unreachable("Unhandled RawValueKey in switch.");
}
};
} // namespace llvm
/// Check the inheritance clause of a type declaration or extension thereof.
///
/// This routine performs detailed checking of the inheritance clause of the
/// given type or extension. It need only be called within the primary source
/// file.
static void checkInheritanceClause(
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> declUnion) {
DeclContext *DC;
MutableArrayRef<TypeLoc> inheritedClause;
ExtensionDecl *ext = nullptr;
TypeDecl *typeDecl = nullptr;
Decl *decl;
if ((ext = declUnion.dyn_cast<ExtensionDecl *>())) {
decl = ext;
DC = ext;
inheritedClause = ext->getInherited();
// Protocol extensions cannot have inheritance clauses.
if (auto proto = ext->getExtendedProtocolDecl()) {
if (!inheritedClause.empty()) {
ext->diagnose(diag::extension_protocol_inheritance,
proto->getName())
.highlight(SourceRange(inheritedClause.front().getSourceRange().Start,
inheritedClause.back().getSourceRange().End));
return;
}
}
} else {
typeDecl = declUnion.get<TypeDecl *>();
decl = typeDecl;
if (auto nominal = dyn_cast<NominalTypeDecl>(typeDecl)) {
DC = nominal;
} else {
DC = typeDecl->getDeclContext();
}
inheritedClause = typeDecl->getInherited();
}
// Can this declaration's inheritance clause contain a class or
// subclass existential?
bool canHaveSuperclass = (isa<ClassDecl>(decl) ||
(isa<ProtocolDecl>(decl) &&
!cast<ProtocolDecl>(decl)->isObjC()));
ASTContext &ctx = decl->getASTContext();
auto &diags = ctx.Diags;
// Retrieve the location of the start of the inheritance clause.
auto getStartLocOfInheritanceClause = [&] {
if (ext)
return ext->getSourceRange().End;
return typeDecl->getNameLoc();
};
// Compute the source range to be used when removing something from an
// inheritance clause.
auto getRemovalRange = [&](unsigned i) {
// If there is just one entry, remove the entire inheritance clause.
if (inheritedClause.size() == 1) {
SourceLoc start = getStartLocOfInheritanceClause();
SourceLoc end = inheritedClause[i].getSourceRange().End;
return SourceRange(Lexer::getLocForEndOfToken(ctx.SourceMgr, start),
Lexer::getLocForEndOfToken(ctx.SourceMgr, end));
}
// If we're at the first entry, remove from the start of this entry to the
// start of the next entry.
if (i == 0) {
return SourceRange(inheritedClause[i].getSourceRange().Start,
inheritedClause[i+1].getSourceRange().Start);
}
// Otherwise, remove from the end of the previous entry to the end of this
// entry.
SourceLoc afterPriorLoc =
Lexer::getLocForEndOfToken(ctx.SourceMgr,
inheritedClause[i-1].getSourceRange().End);
SourceLoc afterMyEndLoc =
Lexer::getLocForEndOfToken(ctx.SourceMgr,
inheritedClause[i].getSourceRange().End);
return SourceRange(afterPriorLoc, afterMyEndLoc);
};
// Check all of the types listed in the inheritance clause.
Type superclassTy;
SourceRange superclassRange;
Optional<std::pair<unsigned, SourceRange>> inheritedAnyObject;
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
auto &inherited = inheritedClause[i];
// Validate the type.
InheritedTypeRequest request{declUnion, i, TypeResolutionStage::Interface};
Type inheritedTy = evaluateOrDefault(ctx.evaluator, request, Type());
// If we couldn't resolve an the inherited type, or it contains an error,
// ignore it.
if (!inheritedTy || inheritedTy->hasError())
continue;
// For generic parameters and associated types, the GSB checks constraints;
// however, we still want to fire off the requests to produce diagnostics
// in some circular validation cases.
if (isa<AbstractTypeParamDecl>(decl))
continue;
// Check whether we inherited from 'AnyObject' twice.
// Other redundant-inheritance scenarios are checked below, the
// GenericSignatureBuilder (for protocol inheritance) or the
// ConformanceLookupTable (for protocol conformance).
if (inheritedTy->isAnyObject()) {
if (inheritedAnyObject) {
// If the first occurrence was written as 'class', downgrade the error
// to a warning in such case for backward compatibility with
// Swift <= 4.
auto knownIndex = inheritedAnyObject->first;
auto knownRange = inheritedAnyObject->second;
SourceRange removeRange = getRemovalRange(knownIndex);
if (!ctx.LangOpts.isSwiftVersionAtLeast(5) &&
(isa<ProtocolDecl>(decl) || isa<AbstractTypeParamDecl>(decl)) &&
Lexer::getTokenAtLocation(ctx.SourceMgr, knownRange.Start)
.is(tok::kw_class)) {
SourceLoc classLoc = knownRange.Start;
diags.diagnose(classLoc, diag::duplicate_anyobject_class_inheritance)
.fixItRemoveChars(removeRange.Start, removeRange.End);
} else {
diags.diagnose(inherited.getSourceRange().Start,
diag::duplicate_inheritance, inheritedTy)
.fixItRemoveChars(removeRange.Start, removeRange.End);
}
continue;
}
// Note that we saw inheritance from 'AnyObject'.
inheritedAnyObject = { i, inherited.getSourceRange() };
}
if (inheritedTy->isExistentialType()) {
auto layout = inheritedTy->getExistentialLayout();
// Subclass existentials are not allowed except on classes and
// non-@objc protocols.
if (layout.explicitSuperclass &&
!canHaveSuperclass) {
decl->diagnose(diag::inheritance_from_protocol_with_superclass,
inheritedTy);
continue;
}
// AnyObject is not allowed except on protocols.
if (layout.hasExplicitAnyObject &&
!isa<ProtocolDecl>(decl)) {
decl->diagnose(canHaveSuperclass
? diag::inheritance_from_non_protocol_or_class
: diag::inheritance_from_non_protocol,
inheritedTy);
continue;
}
// If the existential did not have a class constraint, we're done.
if (!layout.explicitSuperclass)
continue;
// Classes and protocols can inherit from subclass existentials.
// For classes, we check for a duplicate superclass below.
// For protocols, the GSB emits its own warning instead.
if (isa<ProtocolDecl>(decl))
continue;
assert(isa<ClassDecl>(decl));
assert(canHaveSuperclass);
inheritedTy = layout.explicitSuperclass;
}
// If this is an enum inheritance clause, check for a raw type.
if (isa<EnumDecl>(decl)) {
// Check if we already had a raw type.
if (superclassTy) {
if (superclassTy->isEqual(inheritedTy)) {
auto removeRange = getRemovalRange(i);
diags.diagnose(inherited.getSourceRange().Start,
diag::duplicate_inheritance, inheritedTy)
.fixItRemoveChars(removeRange.Start, removeRange.End);
} else {
diags.diagnose(inherited.getSourceRange().Start,
diag::multiple_enum_raw_types, superclassTy,
inheritedTy)
.highlight(superclassRange);
}
continue;
}
// If this is not the first entry in the inheritance clause, complain.
if (i > 0) {
auto removeRange = getRemovalRange(i);
diags.diagnose(inherited.getSourceRange().Start,
diag::raw_type_not_first, inheritedTy)
.fixItRemoveChars(removeRange.Start, removeRange.End)
.fixItInsert(inheritedClause[0].getSourceRange().Start,
inheritedTy.getString() + ", ");
// Fall through to record the raw type.
}
// Record the raw type.
superclassTy = inheritedTy;
superclassRange = inherited.getSourceRange();
continue;
}
// If this is a class type, it may be the superclass. We end up here when
// the inherited type is either itself a class, or when it is a subclass
// existential via the existential type path above.
if (inheritedTy->getClassOrBoundGenericClass()) {
// First, check if we already had a superclass.
if (superclassTy) {
// FIXME: Check for shadowed protocol names, i.e., NSObject?
if (superclassTy->isEqual(inheritedTy)) {
// Duplicate superclass.
auto removeRange = getRemovalRange(i);
diags.diagnose(inherited.getSourceRange().Start,
diag::duplicate_inheritance, inheritedTy)
.fixItRemoveChars(removeRange.Start, removeRange.End);
} else {
// Complain about multiple inheritance.
// Don't emit a Fix-It here. The user has to think harder about this.
diags.diagnose(inherited.getSourceRange().Start,
diag::multiple_inheritance, superclassTy, inheritedTy)
.highlight(superclassRange);
}
continue;
}
// If this is not the first entry in the inheritance clause, complain.
if (isa<ClassDecl>(decl) && i > 0) {
auto removeRange = getRemovalRange(i);
diags.diagnose(inherited.getSourceRange().Start,
diag::superclass_not_first, inheritedTy)
.fixItRemoveChars(removeRange.Start, removeRange.End)
.fixItInsert(inheritedClause[0].getSourceRange().Start,
inheritedTy.getString() + ", ");
// Fall through to record the superclass.
}
if (canHaveSuperclass) {
// Record the superclass.
superclassTy = inheritedTy;
superclassRange = inherited.getSourceRange();
continue;
}
}
// We can't inherit from a non-class, non-protocol type.
decl->diagnose(canHaveSuperclass
? diag::inheritance_from_non_protocol_or_class
: diag::inheritance_from_non_protocol,
inheritedTy);
// FIXME: Note pointing to the declaration 'inheritedTy' references?
}
}
/// Check the inheritance clauses generic parameters along with any
/// requirements stored within the generic parameter list.
static void checkGenericParams(GenericParamList *genericParams,
DeclContext *owningDC, TypeChecker &tc) {
if (!genericParams)
return;
for (auto gp : *genericParams) {
tc.checkDeclAttributes(gp);
checkInheritanceClause(gp);
}
// Force visitation of each of the requirements here.
WhereClauseOwner(owningDC, genericParams)
.visitRequirements(TypeResolutionStage::Interface,
[](Requirement, RequirementRepr *) { return false; });
}
/// Retrieve the set of protocols the given protocol inherits.
static llvm::TinyPtrVector<ProtocolDecl *>
getInheritedForCycleCheck(TypeChecker &tc,
ProtocolDecl *proto,
ProtocolDecl **scratch) {
TinyPtrVector<ProtocolDecl *> result;
bool anyObject = false;
for (const auto &found :
getDirectlyInheritedNominalTypeDecls(proto, anyObject)) {
if (auto protoDecl = dyn_cast<ProtocolDecl>(found.second))
result.push_back(protoDecl);
}
return result;
}
/// Retrieve the superclass of the given class.
static ArrayRef<ClassDecl *> getInheritedForCycleCheck(TypeChecker &tc,
ClassDecl *classDecl,
ClassDecl **scratch) {
if (classDecl->hasSuperclass()) {
*scratch = classDecl->getSuperclassDecl();
return *scratch;
}
return { };
}
/// Retrieve the raw type of the given enum.
static ArrayRef<EnumDecl *> getInheritedForCycleCheck(TypeChecker &tc,
EnumDecl *enumDecl,
EnumDecl **scratch) {
if (enumDecl->hasRawType()) {
*scratch = enumDecl->getRawType()->getEnumOrBoundGenericEnum();
return *scratch ? ArrayRef<EnumDecl*>(*scratch) : ArrayRef<EnumDecl*>{};
}
return { };
}
/// Check for circular inheritance.
template<typename T>
static void checkCircularity(TypeChecker &tc, T *decl,
Diag<Identifier> circularDiag,
DescriptiveDeclKind declKind,
SmallVectorImpl<T *> &path) {
switch (decl->getCircularityCheck()) {
case CircularityCheck::Checked:
return;
case CircularityCheck::Checking: {
// We're already checking this type, which means we have a cycle.
// The beginning of the path might not be part of the cycle, so find
// where the cycle starts.
assert(!path.empty());
auto cycleStart = path.end() - 1;
while (*cycleStart != decl) {
assert(cycleStart != path.begin() && "Missing cycle start?");
--cycleStart;
}
// If the path length is 1 the type directly references itself.
if (path.end() - cycleStart == 1) {
tc.diagnose(path.back()->getLoc(),
circularDiag,
path.back()->getName());
break;
}
// Diagnose the cycle.
tc.diagnose(decl->getLoc(), circularDiag,
(*cycleStart)->getName());
for (auto i = cycleStart + 1, iEnd = path.end(); i != iEnd; ++i) {
tc.diagnose(*i, diag::kind_declname_declared_here,
declKind, (*i)->getName());
}
break;
}
case CircularityCheck::Unchecked: {
// Walk to the inherited class or protocols.
path.push_back(decl);
decl->setCircularityCheck(CircularityCheck::Checking);
T *scratch = nullptr;
for (auto inherited : getInheritedForCycleCheck(tc, decl, &scratch)) {
checkCircularity(tc, inherited, circularDiag, declKind, path);
}
decl->setCircularityCheck(CircularityCheck::Checked);
path.pop_back();
break;
}
}
}
/// Expose TypeChecker's handling of GenericParamList to SIL parsing.
GenericEnvironment *
TypeChecker::handleSILGenericParams(GenericParamList *genericParams,
DeclContext *DC) {
if (genericParams == nullptr)
return nullptr;
SmallVector<GenericParamList *, 2> nestedList;
for (; genericParams; genericParams = genericParams->getOuterParameters()) {
nestedList.push_back(genericParams);
}
std::reverse(nestedList.begin(), nestedList.end());
for (unsigned i = 0, e = nestedList.size(); i < e; ++i) {
auto genericParams = nestedList[i];
genericParams->setDepth(i);
}
auto sig = TypeChecker::checkGenericSignature(
nestedList.back(), DC,
/*parentSig=*/nullptr,
/*allowConcreteGenericParams=*/true);
return (sig ? sig->getGenericEnvironment() : nullptr);
}
/// Check whether \c current is a redeclaration.
static void checkRedeclaration(ASTContext &ctx, ValueDecl *current) {
// If we've already checked this declaration, don't do it again.
if (current->alreadyCheckedRedeclaration())
return;
// Make sure we don't do this checking again.
current->setCheckedRedeclaration(true);
// FIXME: Computes isInvalid() below.
(void) current->getInterfaceType();
// Ignore invalid and anonymous declarations.
if (current->isInvalid() ||
!current->hasInterfaceType() ||
!current->hasName())
return;
// If this declaration isn't from a source file, don't check it.
// FIXME: Should restrict this to the source file we care about.
DeclContext *currentDC = current->getDeclContext();
SourceFile *currentFile = currentDC->getParentSourceFile();
if (!currentFile || currentDC->isLocalContext())
return;
ReferencedNameTracker *tracker = currentFile->getReferencedNameTracker();
bool isCascading = (current->getFormalAccess() > AccessLevel::FilePrivate);
// Find other potential definitions.
SmallVector<ValueDecl *, 4> otherDefinitions;
if (currentDC->isTypeContext()) {
// Look within a type context.
if (auto nominal = currentDC->getSelfNominalTypeDecl()) {
auto found = nominal->lookupDirect(current->getBaseName());
otherDefinitions.append(found.begin(), found.end());
if (tracker)
tracker->addUsedMember({nominal, current->getBaseName()}, isCascading);
}
} else {
// Look within a module context.
currentFile->getParentModule()->lookupValue(current->getBaseName(),
NLKind::QualifiedLookup,
otherDefinitions);
if (tracker)
tracker->addTopLevelName(current->getBaseName(), isCascading);
}
// Compare this signature against the signature of other
// declarations with the same name.
OverloadSignature currentSig = current->getOverloadSignature();
CanType currentSigType = current->getOverloadSignatureType();
ModuleDecl *currentModule = current->getModuleContext();
for (auto other : otherDefinitions) {
// Skip invalid declarations and ourselves.
if (current == other || other->isInvalid())
continue;
// Skip declarations in other modules.
if (currentModule != other->getModuleContext())
continue;
// If both declarations are in the same file, only diagnose the second one.
if (currentFile == other->getDeclContext()->getParentSourceFile())
if (current->getLoc().isValid() &&
ctx.SourceMgr.isBeforeInBuffer(
current->getLoc(), other->getLoc()))
continue;
// Don't compare methods vs. non-methods (which only happens with
// operators).
if (currentDC->isTypeContext() != other->getDeclContext()->isTypeContext())
continue;
// Check whether the overload signatures conflict (ignoring the type for
// now).
auto otherSig = other->getOverloadSignature();
if (!conflicting(currentSig, otherSig))
continue;
// FIXME: Computes isInvalid() below.
(void) other->getInterfaceType();
// Skip invalid declarations.
if (other->isInvalid())
continue;
// Skip declarations in other files.
// In practice, this means we will warn on a private declaration that
// shadows a non-private one, but only in the file where the shadowing
// happens. We will warn on conflicting non-private declarations in both
// files.
if (!other->isAccessibleFrom(currentDC))
continue;
const auto markInvalid = [&current]() {
current->setInvalid();
if (auto *varDecl = dyn_cast<VarDecl>(current))
if (varDecl->hasType())
varDecl->setType(ErrorType::get(varDecl->getType()));
if (current->hasInterfaceType())
current->setInterfaceType(ErrorType::get(current->getInterfaceType()));
};
// Thwart attempts to override the same declaration more than once.
const auto *currentOverride = current->getOverriddenDecl();
const auto *otherOverride = other->getOverriddenDecl();
if (currentOverride && currentOverride == otherOverride) {
current->diagnose(diag::multiple_override, current->getFullName());
other->diagnose(diag::multiple_override_prev, other->getFullName());
markInvalid();
break;
}
// Get the overload signature type.
CanType otherSigType = other->getOverloadSignatureType();
bool wouldBeSwift5Redeclaration = false;
auto isRedeclaration = conflicting(ctx, currentSig, currentSigType,
otherSig, otherSigType,
&wouldBeSwift5Redeclaration);
// If there is another conflict, complain.
if (isRedeclaration || wouldBeSwift5Redeclaration) {
// If the two declarations occur in the same source file, make sure
// we get the diagnostic ordering to be sensible.
if (auto otherFile = other->getDeclContext()->getParentSourceFile()) {
if (currentFile == otherFile &&
current->getLoc().isValid() &&
other->getLoc().isValid() &&
ctx.SourceMgr.isBeforeInBuffer(current->getLoc(),
other->getLoc())) {
std::swap(current, other);
}
}
// If we're currently looking at a .sil and the conflicting declaration
// comes from a .sib, don't error since we won't be considering the sil
// from the .sib. So it's fine for the .sil to shadow it, since that's the
// one we want.
if (currentFile->Kind == SourceFileKind::SIL) {
auto *otherFile = dyn_cast<SerializedASTFile>(
other->getDeclContext()->getModuleScopeContext());
if (otherFile && otherFile->isSIB())
continue;
}
// If the conflicting declarations have non-overlapping availability and,
// we allow the redeclaration to proceed if...
//
// - they are initializers with different failability,
bool isAcceptableVersionBasedChange = false;
{
const auto *currentInit = dyn_cast<ConstructorDecl>(current);
const auto *otherInit = dyn_cast<ConstructorDecl>(other);
if (currentInit && otherInit &&
(currentInit->isFailable() !=
otherInit->isFailable())) {
isAcceptableVersionBasedChange = true;
}
}
// - one throws and the other does not,
{
const auto *currentAFD = dyn_cast<AbstractFunctionDecl>(current);
const auto *otherAFD = dyn_cast<AbstractFunctionDecl>(other);
if (currentAFD && otherAFD &&
currentAFD->hasThrows() != otherAFD->hasThrows()) {
isAcceptableVersionBasedChange = true;
}
}
// - or they are computed properties of different types,
{
const auto *currentVD = dyn_cast<VarDecl>(current);
const auto *otherVD = dyn_cast<VarDecl>(other);
if (currentVD && otherVD &&
!currentVD->hasStorage() &&
!otherVD->hasStorage() &&
!currentVD->getInterfaceType()->isEqual(
otherVD->getInterfaceType())) {
isAcceptableVersionBasedChange = true;
}
}
if (isAcceptableVersionBasedChange) {
class AvailabilityRange {
Optional<llvm::VersionTuple> introduced;
Optional<llvm::VersionTuple> obsoleted;
public:
static AvailabilityRange from(const ValueDecl *VD) {
AvailabilityRange result;
for (auto *attr : VD->getAttrs().getAttributes<AvailableAttr>()) {
if (attr->PlatformAgnostic ==
PlatformAgnosticAvailabilityKind::SwiftVersionSpecific) {
if (attr->Introduced)
result.introduced = attr->Introduced;
if (attr->Obsoleted)
result.obsoleted = attr->Obsoleted;
}
}
return result;
}
bool fullyPrecedes(const AvailabilityRange &other) const {
if (!obsoleted.hasValue())
return false;
if (!other.introduced.hasValue())
return false;
return *obsoleted <= *other.introduced;
}
bool overlaps(const AvailabilityRange &other) const {
return !fullyPrecedes(other) && !other.fullyPrecedes(*this);
}
};
auto currentAvail = AvailabilityRange::from(current);
auto otherAvail = AvailabilityRange::from(other);
if (!currentAvail.overlaps(otherAvail))
continue;
}
// If both are VarDecls, and both have exactly the same type, then
// matching the Swift 4 behaviour (i.e. just emitting the future-compat
// warning) will result in SILGen crashes due to both properties mangling
// the same, so it's better to just follow the Swift 5 behaviour and emit
// the actual error.
if (wouldBeSwift5Redeclaration && isa<VarDecl>(current) &&
isa<VarDecl>(other) &&
current->getInterfaceType()->isEqual(other->getInterfaceType())) {
wouldBeSwift5Redeclaration = false;
}
// If this isn't a redeclaration in the current version of Swift, but
// would be in Swift 5 mode, emit a warning instead of an error.
if (wouldBeSwift5Redeclaration) {
current->diagnose(diag::invalid_redecl_swift5_warning,
current->getFullName());
other->diagnose(diag::invalid_redecl_prev, other->getFullName());
} else {
const auto *otherInit = dyn_cast<ConstructorDecl>(other);
// Provide a better description for implicit initializers.
if (otherInit && otherInit->isImplicit()) {
// Skip conflicts with inherited initializers, which only happen
// when the current declaration is within an extension. The override
// checker should have already taken care of emitting a more
// productive diagnostic.
if (!other->getOverriddenDecl())
current->diagnose(diag::invalid_redecl_init,
current->getFullName(),
otherInit->isMemberwiseInitializer());
} else {
ctx.Diags.diagnoseWithNotes(
current->diagnose(diag::invalid_redecl,
current->getFullName()), [&]() {
other->diagnose(diag::invalid_redecl_prev, other->getFullName());
});
}
markInvalid();
}
// Make sure we don't do this checking again for the same decl. We also
// set this at the beginning of the function, but we might have swapped
// the decls for diagnostics; so ensure we also set this for the actual
// decl we diagnosed on.
current->setCheckedRedeclaration(true);
break;
}
}
}
namespace {
// The raw values of this enum must be kept in sync with
// diag::implicitly_final_cannot_be_open.
enum class ImplicitlyFinalReason : unsigned {
/// A property was declared with 'let'.
Let,
/// The containing class is final.
FinalClass,
/// A member was declared as 'static'.
Static
};
}
static bool inferFinalAndDiagnoseIfNeeded(ValueDecl *D, ClassDecl *cls,
StaticSpellingKind staticSpelling) {
// Are there any reasons to infer 'final'? Prefer 'static' over the class
// being final for the purposes of diagnostics.
Optional<ImplicitlyFinalReason> reason;
if (staticSpelling == StaticSpellingKind::KeywordStatic) {
reason = ImplicitlyFinalReason::Static;
if (auto finalAttr = D->getAttrs().getAttribute<FinalAttr>()) {
auto finalRange = finalAttr->getRange();
if (finalRange.isValid()) {
auto &context = D->getASTContext();
context.Diags.diagnose(finalRange.Start, diag::static_decl_already_final)
.fixItRemove(finalRange);
}
}
} else if (cls->isFinal()) {
reason = ImplicitlyFinalReason::FinalClass;
}
if (!reason)
return false;
if (D->getFormalAccess() == AccessLevel::Open) {
auto &context = D->getASTContext();
auto diagID = diag::implicitly_final_cannot_be_open;
if (!context.isSwiftVersionAtLeast(5))
diagID = diag::implicitly_final_cannot_be_open_swift4;
auto inFlightDiag = context.Diags.diagnose(D, diagID,
static_cast<unsigned>(reason.getValue()));
fixItAccess(inFlightDiag, D, AccessLevel::Public);
}
return true;
}
/// Runtime-replacable accessors are dynamic when their storage declaration
/// is dynamic and they were explicitly defined or they are implicitly defined
/// getter/setter because no accessor was defined.
static bool doesAccessorNeedDynamicAttribute(AccessorDecl *accessor) {
auto kind = accessor->getAccessorKind();
auto storage = accessor->getStorage();
bool isObjC = storage->isObjC();
switch (kind) {
case AccessorKind::Get: {
auto readImpl = storage->getReadImpl();
if (!isObjC &&
(readImpl == ReadImplKind::Read || readImpl == ReadImplKind::Address))
return false;
return storage->isDynamic();
}
case AccessorKind::Set: {
auto writeImpl = storage->getWriteImpl();
if (!isObjC && (writeImpl == WriteImplKind::Modify ||
writeImpl == WriteImplKind::MutableAddress ||
writeImpl == WriteImplKind::StoredWithObservers))
return false;
return storage->isDynamic();
}
case AccessorKind::Read:
if (!isObjC && storage->getReadImpl() == ReadImplKind::Read)
return storage->isDynamic();
return false;
case AccessorKind::Modify: {
if (!isObjC && storage->getWriteImpl() == WriteImplKind::Modify)
return storage->isDynamic();
return false;
}
case AccessorKind::MutableAddress: {
if (!isObjC && storage->getWriteImpl() == WriteImplKind::MutableAddress)
return storage->isDynamic();
return false;
}
case AccessorKind::Address: {
if (!isObjC && storage->getReadImpl() == ReadImplKind::Address)
return storage->isDynamic();
return false;
}
case AccessorKind::DidSet:
case AccessorKind::WillSet:
if (!isObjC &&
storage->getWriteImpl() == WriteImplKind::StoredWithObservers)
return storage->isDynamic();
return false;
}
llvm_unreachable("covered switch");
}
llvm::Expected<CtorInitializerKind>
InitKindRequest::evaluate(Evaluator &evaluator, ConstructorDecl *decl) const {
auto &diags = decl->getASTContext().Diags;
// Convenience inits are only allowed on classes and in extensions thereof.
if (decl->getAttrs().hasAttribute<ConvenienceAttr>()) {
if (auto nominal = decl->getDeclContext()->getSelfNominalTypeDecl()) {
auto classDecl = dyn_cast<ClassDecl>(nominal);
// Forbid convenience inits on Foreign CF types, as Swift does not yet
// support user-defined factory inits.
if (classDecl &&
classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType) {
diags.diagnose(decl->getLoc(), diag::cfclass_convenience_init);
}
if (!classDecl) {
auto ConvenienceLoc =
decl->getAttrs().getAttribute<ConvenienceAttr>()->getLocation();
// Produce a tailored diagnostic for structs and enums.
bool isStruct = dyn_cast<StructDecl>(nominal) != nullptr;
if (isStruct || dyn_cast<EnumDecl>(nominal)) {
diags.diagnose(decl->getLoc(), diag::enumstruct_convenience_init,
isStruct ? "structs" : "enums")
.fixItRemove(ConvenienceLoc);
} else {
diags.diagnose(decl->getLoc(), diag::nonclass_convenience_init,
nominal->getName())
.fixItRemove(ConvenienceLoc);
}
return CtorInitializerKind::Designated;
}
}
return CtorInitializerKind::Convenience;
} else if (auto nominal = decl->getDeclContext()->getSelfNominalTypeDecl()) {
// A designated init for a class must be written within the class itself.
//
// This is because designated initializers of classes get a vtable entry,
// and extensions cannot add vtable entries to the extended type.
//
// If we implement the ability for extensions defined in the same module
// (or the same file) to add vtable entries, we can re-evaluate this
// restriction.
if (dyn_cast<ClassDecl>(nominal) &&
!decl->isSynthesized() && isa<ExtensionDecl>(decl->getDeclContext()) &&
!(decl->getAttrs().hasAttribute<DynamicReplacementAttr>())) {
diags.diagnose(decl->getLoc(), diag::designated_init_in_extension,
nominal->getName())
.fixItInsert(decl->getLoc(), "convenience ");
return CtorInitializerKind::Convenience;
}
if (decl->getDeclContext()->getExtendedProtocolDecl()) {
return CtorInitializerKind::Convenience;
}
}
return CtorInitializerKind::Designated;
}
llvm::Expected<bool>
ProtocolRequiresClassRequest::evaluate(Evaluator &evaluator,
ProtocolDecl *decl) const {
// Quick check: @objc protocols require a class.
if (decl->isObjC())
return true;
// Determine the set of nominal types that this protocol inherits.
bool anyObject = false;
auto allInheritedNominals =
getDirectlyInheritedNominalTypeDecls(decl, anyObject);
// Quick check: do we inherit AnyObject?
if (anyObject)
return true;
// Look through all of the inherited nominals for a superclass or a
// class-bound protocol.
for (const auto found : allInheritedNominals) {
// Superclass bound.
if (isa<ClassDecl>(found.second))
return true;
// A protocol that might be class-constrained.
if (auto proto = dyn_cast<ProtocolDecl>(found.second)) {
if (proto->requiresClass())
return true;
}
}
return false;
}
llvm::Expected<bool>
ExistentialConformsToSelfRequest::evaluate(Evaluator &evaluator,
ProtocolDecl *decl) const {
// If it's not @objc, it conforms to itself only if it has a self-conformance
// witness table.
if (!decl->isObjC())
return decl->requiresSelfConformanceWitnessTable();
// Check whether this protocol conforms to itself.
for (auto member : decl->getMembers()) {
if (member->isInvalid()) continue;
if (auto vd = dyn_cast<ValueDecl>(member)) {
// A protocol cannot conform to itself if it has static members.
if (!vd->isInstanceMember())
return false;
}
}
// Check whether any of the inherited protocols fail to conform to themselves.
for (auto proto : decl->getInheritedProtocols()) {
if (!proto->existentialConformsToSelf())
return false;
}
return true;
}
llvm::Expected<bool>
ExistentialTypeSupportedRequest::evaluate(Evaluator &evaluator,
ProtocolDecl *decl) const {
// ObjC protocols can always be existential.
if (decl->isObjC())
return true;
for (auto member : decl->getMembers()) {
// Existential types cannot be used if the protocol has an associated type.
if (isa<AssociatedTypeDecl>(member))
return false;
// For value members, look at their type signatures.
if (auto valueMember = dyn_cast<ValueDecl>(member)) {
if (!decl->isAvailableInExistential(valueMember))
return false;
}
}
// Check whether all of the inherited protocols support existential types.
for (auto proto : decl->getInheritedProtocols()) {
if (!proto->existentialTypeSupported())
return false;
}
return true;
}
llvm::Expected<bool>
IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
if (isa<ClassDecl>(decl))
return decl->getAttrs().hasAttribute<FinalAttr>();
auto cls = decl->getDeclContext()->getSelfClassDecl();
if (!cls)
return false;
switch (decl->getKind()) {
case DeclKind::Var: {
// Properties are final if they are declared 'static' or a 'let'
auto *VD = cast<VarDecl>(decl);
// Backing storage for 'lazy' or property wrappers is always final.
if (VD->isLazyStorageProperty() ||
VD->getOriginalWrappedProperty(PropertyWrapperSynthesizedPropertyKind::Backing))
return true;
if (auto *nominalDecl = VD->getDeclContext()->getSelfClassDecl()) {
// If this variable is a class member, mark it final if the
// class is final, or if it was declared with 'let'.
auto *PBD = VD->getParentPatternBinding();
if (PBD && inferFinalAndDiagnoseIfNeeded(decl, cls, PBD->getStaticSpelling()))
return true;
if (VD->isLet()) {
if (VD->getFormalAccess() == AccessLevel::Open) {
auto &context = decl->getASTContext();
auto diagID = diag::implicitly_final_cannot_be_open;
if (!context.isSwiftVersionAtLeast(5))
diagID = diag::implicitly_final_cannot_be_open_swift4;
auto inFlightDiag =
context.Diags.diagnose(decl, diagID,
static_cast<unsigned>(ImplicitlyFinalReason::Let));
fixItAccess(inFlightDiag, decl, AccessLevel::Public);
}
return true;
}
}
break;
}
case DeclKind::Func: {
// Methods declared 'static' are final.
auto staticSpelling = cast<FuncDecl>(decl)->getStaticSpelling();
if (inferFinalAndDiagnoseIfNeeded(decl, cls, staticSpelling))
return true;
break;
}
case DeclKind::Accessor:
if (auto accessor = dyn_cast<AccessorDecl>(decl)) {
switch (accessor->getAccessorKind()) {
case AccessorKind::DidSet:
case AccessorKind::WillSet:
// Observing accessors are marked final if in a class.
return true;
case AccessorKind::Read:
case AccessorKind::Modify:
case AccessorKind::Get:
case AccessorKind::Set: {
// Coroutines and accessors are final if their storage is.
auto storage = accessor->getStorage();
if (storage->isFinal())
return true;
break;
}
default:
break;
}
}
break;
case DeclKind::Subscript: {
// Member subscripts.
auto staticSpelling = cast<SubscriptDecl>(decl)->getStaticSpelling();
if (inferFinalAndDiagnoseIfNeeded(decl, cls, staticSpelling))
return true;
break;
}
default:
break;
}
if (decl->getAttrs().hasAttribute<FinalAttr>())
return true;
return false;
}
llvm::Expected<bool>
IsStaticRequest::evaluate(Evaluator &evaluator, FuncDecl *decl) const {
if (auto *accessor = dyn_cast<AccessorDecl>(decl))
return accessor->getStorage()->isStatic();
bool result = (decl->getStaticLoc().isValid() ||
decl->getStaticSpelling() != StaticSpellingKind::None);
auto *dc = decl->getDeclContext();
if (!result &&
decl->isOperator() &&
dc->isTypeContext()) {
auto operatorName = decl->getFullName().getBaseIdentifier();
decl->diagnose(diag::nonstatic_operator_in_type,
operatorName, dc->getDeclaredInterfaceType())
.fixItInsert(decl->getAttributeInsertionLoc(/*forModifier=*/true),
"static ");
result = true;
}
return result;
}
llvm::Expected<bool>
IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
// If we can't infer dynamic here, don't.
if (!DeclAttribute::canAttributeAppearOnDecl(DAK_Dynamic, decl))
return false;
// Add dynamic if -enable-implicit-dynamic was requested.
TypeChecker::addImplicitDynamicAttribute(decl);
// If 'dynamic' was explicitly specified, check it.
if (decl->getAttrs().hasAttribute<DynamicAttr>()) {
return true;
}
if (auto accessor = dyn_cast<AccessorDecl>(decl)) {
// Runtime-replacable accessors are dynamic when their storage declaration
// is dynamic and they were explicitly defined or they are implicitly defined
// getter/setter because no accessor was defined.
return doesAccessorNeedDynamicAttribute(accessor);
}
// The 'NSManaged' attribute implies 'dynamic'.
// FIXME: Use a semantic check for NSManaged rather than looking for the
// attribute (which could be ill-formed).
if (decl->getAttrs().hasAttribute<NSManagedAttr>())
return true;
// The presence of 'final' blocks the inference of 'dynamic'.
if (decl->isFinal())
return false;
// Types are never 'dynamic'.
if (isa<TypeDecl>(decl))
return false;
// A non-@objc entity is never 'dynamic'.
if (!decl->isObjC())
return false;
// @objc declarations in class extensions are implicitly dynamic.
// This is intended to enable overriding the declarations.
auto dc = decl->getDeclContext();
if (isa<ExtensionDecl>(dc) && dc->getSelfClassDecl())
return true;
// If any of the declarations overridden by this declaration are dynamic
// or were imported from Objective-C, this declaration is dynamic.
// Don't do this if the declaration is not exposed to Objective-C; that's
// currently the (only) manner in which one can make an override of a
// dynamic declaration non-dynamic.
auto overriddenDecls = evaluateOrDefault(evaluator,
OverriddenDeclsRequest{decl}, {});
for (auto overridden : overriddenDecls) {
if (overridden->isDynamic() || overridden->hasClangNode())
return true;
}
return false;
}
llvm::Expected<ArrayRef<Requirement>>
RequirementSignatureRequest::evaluate(Evaluator &evaluator,
ProtocolDecl *proto) const {
ASTContext &ctx = proto->getASTContext();
// First check if we have a deserializable requirement signature.
if (proto->hasLazyRequirementSignature()) {
++NumLazyRequirementSignaturesLoaded;
// FIXME: (transitional) increment the redundant "always-on" counter.
if (ctx.Stats)
ctx.Stats->getFrontendCounters().NumLazyRequirementSignaturesLoaded++;
auto contextData = static_cast<LazyProtocolData *>(
ctx.getOrCreateLazyContextData(proto, nullptr));
SmallVector<Requirement, 8> requirements;
contextData->loader->loadRequirementSignature(
proto, contextData->requirementSignatureData, requirements);
if (requirements.empty())
return None;
return ctx.AllocateCopy(requirements);
}
GenericSignatureBuilder builder(proto->getASTContext());
// Add all of the generic parameters.
for (auto gp : *proto->getGenericParams())
builder.addGenericParameter(gp);
// Add the conformance of 'self' to the protocol.
auto selfType =
proto->getSelfInterfaceType()->castTo<GenericTypeParamType>();
auto requirement =
Requirement(RequirementKind::Conformance, selfType,
proto->getDeclaredInterfaceType());
builder.addRequirement(
requirement,
GenericSignatureBuilder::RequirementSource::forRequirementSignature(
builder, selfType, proto),
nullptr);
auto reqSignature = std::move(builder).computeGenericSignature(
SourceLoc(),
/*allowConcreteGenericPArams=*/false,
/*allowBuilderToMove=*/false);
return reqSignature->getRequirements();
}
llvm::Expected<Type>
DefaultDefinitionTypeRequest::evaluate(Evaluator &evaluator,
AssociatedTypeDecl *assocType) const {
if (assocType->Resolver) {
auto defaultType = assocType->Resolver->loadAssociatedTypeDefault(
assocType, assocType->ResolverContextData);
assocType->Resolver = nullptr;
return defaultType;
}
TypeRepr *defaultDefinition = assocType->getDefaultDefinitionTypeRepr();
if (defaultDefinition) {
auto resolution = TypeResolution::forInterface(assocType->getDeclContext());
return resolution.resolveType(defaultDefinition, None);
}
return Type();
}
llvm::Expected<bool>
NeedsNewVTableEntryRequest::evaluate(Evaluator &evaluator,
AbstractFunctionDecl *decl) const {
auto *dc = decl->getDeclContext();
if (!isa<ClassDecl>(dc))
return true;
assert(isa<FuncDecl>(decl) || isa<ConstructorDecl>(decl));
// Final members are always be called directly.
// Dynamic methods are always accessed by objc_msgSend().
if (decl->isFinal() || decl->isObjCDynamic() || decl->hasClangNode())
return false;
auto &ctx = dc->getASTContext();
// Initializers are not normally inherited, but required initializers can
// be overridden for invocation from dynamic types, and convenience initializers
// are conditionally inherited when all designated initializers are available,
// working by dynamically invoking the designated initializer implementation
// from the subclass. Convenience initializers can also override designated
// initializer implementations from their superclass.
if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
if (!ctor->isRequired() && !ctor->isDesignatedInit()) {
return false;
}
// Stub constructors don't appear in the vtable.
if (ctor->hasStubImplementation())
return false;
}
if (auto *accessor = dyn_cast<AccessorDecl>(decl)) {
// Check to see if it's one of the opaque accessors for the declaration.
auto storage = accessor->getStorage();
if (!storage->requiresOpaqueAccessor(accessor->getAccessorKind()))
return false;
}
auto base = decl->getOverriddenDecl();
if (!base || base->hasClangNode() || base->isObjCDynamic())
return true;
// As above, convenience initializers are not formally overridable in Swift
// vtables, although same-named initializers are modeled as overriding for
// various QoI and objc interop reasons. Even if we "override" a non-required
// convenience init, we still need a distinct vtable entry.
if (auto baseCtor = dyn_cast<ConstructorDecl>(base)) {
if (!baseCtor->isRequired() && !baseCtor->isDesignatedInit()) {
return true;
}
}
// If the base is less visible than the override, we might need a vtable
// entry since callers of the override might not be able to see the base
// at all.
if (decl->isEffectiveLinkageMoreVisibleThan(base))
return true;
using Direction = ASTContext::OverrideGenericSignatureReqCheck;
if (!ctx.overrideGenericSignatureReqsSatisfied(
base, decl, Direction::BaseReqSatisfiedByDerived)) {
return true;
}
// If this method is an ABI compatible override, then we don't need a new
// vtable entry. Otherwise, if it's not ABI compatible, for example if the
// base has a more general AST type, then we need a new entry. Note that an
// abstraction change is OK; we don't want to add a whole new vtable entry
// just because an @in parameter becomes @owned, or whatever.
auto isABICompatibleOverride =
evaluateOrDefault(evaluator, IsABICompatibleOverrideRequest{decl}, false);
return !isABICompatibleOverride;
}
namespace {
/// How to generate the raw value for each element of an enum that doesn't
/// have one explicitly specified.
enum class AutomaticEnumValueKind {
/// Raw values cannot be automatically generated.
None,
/// The raw value is the enum element's name.
String,
/// The raw value is the previous element's raw value, incremented.
///
/// For the first element in the enum, the raw value is 0.
Integer,
};
} // end anonymous namespace
/// Given the raw value literal expression for an enum case, produces the
/// auto-incremented raw value for the subsequent case, or returns null if
/// the value is not auto-incrementable.
static LiteralExpr *getAutomaticRawValueExpr(AutomaticEnumValueKind valueKind,
EnumElementDecl *forElt,
LiteralExpr *prevValue) {
auto &Ctx = forElt->getASTContext();
switch (valueKind) {
case AutomaticEnumValueKind::None:
Ctx.Diags.diagnose(forElt->getLoc(),
diag::enum_non_integer_convertible_raw_type_no_value);
return nullptr;
case AutomaticEnumValueKind::String:
return new (Ctx) StringLiteralExpr(forElt->getNameStr(), SourceLoc(),
/*Implicit=*/true);
case AutomaticEnumValueKind::Integer:
// If there was no previous value, start from zero.
if (!prevValue) {
return new (Ctx) IntegerLiteralExpr("0", SourceLoc(),
/*Implicit=*/true);
}
if (auto intLit = dyn_cast<IntegerLiteralExpr>(prevValue)) {
APInt nextVal = intLit->getRawValue().sextOrSelf(128) + 1;
bool negative = nextVal.slt(0);
if (negative)
nextVal = -nextVal;
llvm::SmallString<10> nextValStr;
nextVal.toStringSigned(nextValStr);
auto expr = new (Ctx)
IntegerLiteralExpr(Ctx.AllocateCopy(StringRef(nextValStr)),
forElt->getLoc(), /*Implicit=*/true);
if (negative)
expr->setNegative(forElt->getLoc());
return expr;
}
Ctx.Diags.diagnose(forElt->getLoc(),
diag::enum_non_integer_raw_value_auto_increment);
return nullptr;
}
llvm_unreachable("Unhandled AutomaticEnumValueKind in switch.");
}
static Optional<AutomaticEnumValueKind>
computeAutomaticEnumValueKind(EnumDecl *ED) {
Type rawTy = ED->getRawType();
assert(rawTy && "Cannot compute value kind without raw type!");
if (ED->getGenericEnvironmentOfContext() != nullptr)
rawTy = ED->mapTypeIntoContext(rawTy);
// Swift enums require that the raw type is convertible from one of the
// primitive literal protocols.
auto conformsToProtocol = [&](KnownProtocolKind protoKind) {
ProtocolDecl *proto = ED->getASTContext().getProtocol(protoKind);
return TypeChecker::conformsToProtocol(rawTy, proto,
ED->getDeclContext(), None);
};
static auto otherLiteralProtocolKinds = {
KnownProtocolKind::ExpressibleByFloatLiteral,
KnownProtocolKind::ExpressibleByUnicodeScalarLiteral,
KnownProtocolKind::ExpressibleByExtendedGraphemeClusterLiteral,
};
if (conformsToProtocol(KnownProtocolKind::ExpressibleByIntegerLiteral)) {
return AutomaticEnumValueKind::Integer;
} else if (conformsToProtocol(KnownProtocolKind::ExpressibleByStringLiteral)){
return AutomaticEnumValueKind::String;
} else if (std::any_of(otherLiteralProtocolKinds.begin(),
otherLiteralProtocolKinds.end(),
conformsToProtocol)) {
return AutomaticEnumValueKind::None;
} else {
return None;
}
}
llvm::Expected<bool>
EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED,
TypeResolutionStage stage) const {
Type rawTy = ED->getRawType();
if (!rawTy) {
return true;
}
if (ED->getGenericEnvironmentOfContext() != nullptr)
rawTy = ED->mapTypeIntoContext(rawTy);
if (rawTy->hasError())
return true;
// Check the raw values of the cases.
LiteralExpr *prevValue = nullptr;
EnumElementDecl *lastExplicitValueElt = nullptr;
// Keep a map we can use to check for duplicate case values.
llvm::SmallDenseMap<RawValueKey, RawValueSource, 8> uniqueRawValues;
// Make the raw member accesses explicit.
auto uncheckedRawValueOf = [](EnumElementDecl *EED) -> LiteralExpr * {
return EED->RawValueExpr;
};
Optional<AutomaticEnumValueKind> valueKind;
for (auto elt : ED->getAllElements()) {
// FIXME: Computes isInvalid() below.
(void) elt->getInterfaceType();
// If the element has been diagnosed up to now, skip it.
if (elt->isInvalid())
continue;
if (uncheckedRawValueOf(elt)) {
if (!uncheckedRawValueOf(elt)->isImplicit())
lastExplicitValueElt = elt;
} else if (!ED->LazySemanticInfo.hasFixedRawValues()) {
// Try to pull out the automatic enum value kind. If that fails, bail.
if (!valueKind) {
valueKind = computeAutomaticEnumValueKind(ED);
if (!valueKind) {
elt->setInvalid();
return true;
}
}
// If the enum element has no explicit raw value, try to
// autoincrement from the previous value, or start from zero if this
// is the first element.
auto nextValue = getAutomaticRawValueExpr(*valueKind, elt, prevValue);
if (!nextValue) {
elt->setInvalid();
break;
}
elt->setRawValueExpr(nextValue);
}
prevValue = uncheckedRawValueOf(elt);
assert(prevValue && "continued without setting raw value of enum case");
switch (stage) {
case TypeResolutionStage::Structural:
// We're only interested in computing the complete set of raw values,
// so we can skip type checking.
continue;
default:
// Continue on to type check the raw value.
break;
}
{
auto *TC = static_cast<TypeChecker *>(ED->getASTContext().getLazyResolver());
assert(TC && "Must have a lazy resolver set");
Expr *exprToCheck = prevValue;
if (TC->typeCheckExpression(exprToCheck, ED, TypeLoc::withoutLoc(rawTy),
CTP_EnumCaseRawValue)) {
TC->checkEnumElementErrorHandling(elt, exprToCheck);
}
}
// If we didn't find a valid initializer (maybe the initial value was
// incompatible with the raw value type) mark the entry as being erroneous.
if (!prevValue->getType() || prevValue->getType()->hasError()) {
elt->setInvalid();
continue;
}
// If the raw values of the enum case are fixed, then we trust our callers
// to have set things up correctly. This comes up with imported enums
// and deserialized @objc enums which always have their raw values setup
// beforehand.
if (ED->LazySemanticInfo.hasFixedRawValues())
continue;
// Check that the raw value is unique.
RawValueKey key{prevValue};
RawValueSource source{elt, lastExplicitValueElt};
auto insertIterPair = uniqueRawValues.insert({key, source});
if (insertIterPair.second)
continue;
// Diagnose the duplicate value.
auto &Diags = ED->getASTContext().Diags;
SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit()
? elt->getLoc() : uncheckedRawValueOf(elt)->getLoc();
Diags.diagnose(diagLoc, diag::enum_raw_value_not_unique);
assert(lastExplicitValueElt &&
"should not be able to have non-unique raw values when "
"relying on autoincrement");
if (lastExplicitValueElt != elt &&
valueKind == AutomaticEnumValueKind::Integer) {
Diags.diagnose(uncheckedRawValueOf(lastExplicitValueElt)->getLoc(),
diag::enum_raw_value_incrementing_from_here);
}
RawValueSource prevSource = insertIterPair.first->second;
auto foundElt = prevSource.sourceElt;
diagLoc = uncheckedRawValueOf(foundElt)->isImplicit()
? foundElt->getLoc() : uncheckedRawValueOf(foundElt)->getLoc();
Diags.diagnose(diagLoc, diag::enum_raw_value_used_here);
if (foundElt != prevSource.lastExplicitValueElt &&
valueKind == AutomaticEnumValueKind::Integer) {
if (prevSource.lastExplicitValueElt)
Diags.diagnose(uncheckedRawValueOf(prevSource.lastExplicitValueElt)
->getLoc(),
diag::enum_raw_value_incrementing_from_here);
else
Diags.diagnose(ED->getAllElements().front()->getLoc(),
diag::enum_raw_value_incrementing_from_zero);
}
}
return true;
}
const ConstructorDecl *
swift::findNonImplicitRequiredInit(const ConstructorDecl *CD) {
while (CD->isImplicit()) {
auto *overridden = CD->getOverriddenDecl();
if (!overridden || !overridden->isRequired())
break;
CD = overridden;
}
return CD;
}
/// For building the higher-than component of the diagnostic path,
/// we use the visited set, which we've embellished with information
/// about how we reached a particular node. This is reasonable because
/// we need to maintain the set anyway.
static void buildHigherThanPath(
PrecedenceGroupDecl *last,
const llvm::DenseMap<PrecedenceGroupDecl *, PrecedenceGroupDecl *>
&visitedFrom,
raw_ostream &out) {
auto it = visitedFrom.find(last);
assert(it != visitedFrom.end());
auto from = it->second;
if (from) {
buildHigherThanPath(from, visitedFrom, out);
}
out << last->getName() << " -> ";
}
/// For building the lower-than component of the diagnostic path,
/// we just do a depth-first search to find a path.
static bool buildLowerThanPath(PrecedenceGroupDecl *start,
PrecedenceGroupDecl *target, raw_ostream &out) {
if (start == target) {
out << start->getName();
return true;
}
if (start->isInvalid())
return false;
for (auto &rel : start->getLowerThan()) {
if (rel.Group && buildLowerThanPath(rel.Group, target, out)) {
out << " -> " << start->getName();
return true;
}
}
return false;
}
static void checkPrecedenceCircularity(DiagnosticEngine &D,
PrecedenceGroupDecl *PGD) {
// Don't diagnose if this group is already marked invalid.
if (PGD->isInvalid())
return;
// The cycle doesn't necessarily go through this specific group,
// so we need a proper visited set to avoid infinite loops. We
// also record a back-reference so that we can easily reconstruct
// the cycle.
llvm::DenseMap<PrecedenceGroupDecl *, PrecedenceGroupDecl *> visitedFrom;
SmallVector<PrecedenceGroupDecl *, 4> stack;
// Fill out the targets set.
llvm::SmallPtrSet<PrecedenceGroupDecl *, 4> targets;
stack.push_back(PGD);
do {
auto cur = stack.pop_back_val();
// If we reach an invalid node, just bail out.
if (cur->isInvalid()) {
PGD->setInvalid();
return;
}
targets.insert(cur);
for (auto &rel : cur->getLowerThan()) {
if (!rel.Group)
continue;
// We can't have cycles in the lower-than relationship
// because it has to point outside of the module.
stack.push_back(rel.Group);
}
} while (!stack.empty());
// Make sure that the PGD is its own source.
visitedFrom.insert({PGD, nullptr});
stack.push_back(PGD);
do {
auto cur = stack.pop_back_val();
// If we reach an invalid node, just bail out.
if (cur->isInvalid()) {
PGD->setInvalid();
return;
}
for (auto &rel : cur->getHigherThan()) {
if (!rel.Group)
continue;
// Check whether we've reached a target declaration.
if (!targets.count(rel.Group)) {
// If not, check whether we've visited this group before.
if (visitedFrom.insert({rel.Group, cur}).second) {
// If not, add it to the queue.
stack.push_back(rel.Group);
}
// Note that we'll silently ignore cycles that don't go through PGD.
// We should eventually process the groups that are involved.
continue;
}
// Otherwise, we have something to report.
SmallString<128> path;
{
llvm::raw_svector_ostream str(path);
// Build the higherThan portion of the path (PGD -> cur).
buildHigherThanPath(cur, visitedFrom, str);
// Build the lowerThan portion of the path (rel.Group -> PGD).
buildLowerThanPath(PGD, rel.Group, str);
}
D.diagnose(PGD->getHigherThanLoc(), diag::precedence_group_cycle, path);
PGD->setInvalid();
return;
}
} while (!stack.empty());
}
static void validatePrecedenceGroup(PrecedenceGroupDecl *PGD) {
assert(PGD && "Cannot validate a null precedence group!");
if (PGD->isInvalid() || PGD->hasValidationStarted())
return;
DeclValidationRAII IBV(PGD);
auto &Diags = PGD->getASTContext().Diags;
// Validate the higherThan relationships.
bool addedHigherThan = false;
for (auto &rel : PGD->getMutableHigherThan()) {
if (rel.Group) continue;
auto group = TypeChecker::lookupPrecedenceGroup(PGD->getDeclContext(),
rel.Name, rel.NameLoc);
if (group) {
rel.Group = group;
addedHigherThan = true;
} else if (!PGD->isInvalid()) {
Diags.diagnose(rel.NameLoc, diag::unknown_precedence_group, rel.Name);
PGD->setInvalid();
}
}
// Validate the lowerThan relationships.
for (auto &rel : PGD->getMutableLowerThan()) {
if (rel.Group) continue;
auto dc = PGD->getDeclContext();
auto group = TypeChecker::lookupPrecedenceGroup(dc, rel.Name, rel.NameLoc);
if (group) {
if (group->getDeclContext()->getParentModule() == dc->getParentModule()) {
if (!PGD->isInvalid()) {
Diags.diagnose(rel.NameLoc,
diag::precedence_group_lower_within_module);
Diags.diagnose(group->getNameLoc(), diag::kind_declared_here,
DescriptiveDeclKind::PrecedenceGroup);
PGD->setInvalid();
}
} else {
rel.Group = group;
}
} else if (!PGD->isInvalid()) {
Diags.diagnose(rel.NameLoc, diag::unknown_precedence_group, rel.Name);
PGD->setInvalid();
}
}
// Check for circularity.
if (addedHigherThan) {
checkPrecedenceCircularity(Diags, PGD);
}
}
static Optional<unsigned>
getParamIndex(const ParameterList *paramList, const ParamDecl *decl) {
ArrayRef<ParamDecl *> params = paramList->getArray();
for (unsigned i = 0; i < params.size(); ++i) {
if (params[i] == decl) return i;
}
return None;
}
static void
checkInheritedDefaultValueRestrictions(TypeChecker &TC, ParamDecl *PD) {
if (PD->getDefaultArgumentKind() != DefaultArgumentKind::Inherited)
return;
auto *DC = PD->getInnermostDeclContext();
const SourceFile *SF = DC->getParentSourceFile();
assert((SF && SF->Kind == SourceFileKind::Interface || PD->isImplicit()) &&
"explicit inherited default argument outside of a module interface?");
// The containing decl should be a designated initializer.
auto ctor = dyn_cast<ConstructorDecl>(DC);
if (!ctor || ctor->isConvenienceInit()) {
TC.diagnose(
PD, diag::inherited_default_value_not_in_designated_constructor);
return;
}
// The decl it overrides should also be a designated initializer.
auto overridden = ctor->getOverriddenDecl();
if (!overridden || overridden->isConvenienceInit()) {
TC.diagnose(
PD, diag::inherited_default_value_used_in_non_overriding_constructor);
if (overridden)
TC.diagnose(overridden, diag::overridden_here);
return;
}
// The corresponding parameter should have a default value.
Optional<unsigned> idx = getParamIndex(ctor->getParameters(), PD);
assert(idx && "containing decl does not contain param?");
ParamDecl *equivalentParam = overridden->getParameters()->get(*idx);
if (equivalentParam->getDefaultArgumentKind() == DefaultArgumentKind::None) {
TC.diagnose(PD, diag::corresponding_param_not_defaulted);
TC.diagnose(equivalentParam, diag::inherited_default_param_here);
}
}
/// Check the default arguments that occur within this pattern.
static void checkDefaultArguments(TypeChecker &tc, ParameterList *params,
ValueDecl *VD) {
for (auto *param : *params) {
checkInheritedDefaultValueRestrictions(tc, param);
if (!param->getDefaultValue() ||
!param->hasInterfaceType() ||
param->getInterfaceType()->hasError())
continue;
Expr *e = param->getDefaultValue();
auto *initContext = param->getDefaultArgumentInitContext();
auto resultTy =
tc.typeCheckParameterDefault(e, initContext, param->getType(),
/*isAutoClosure=*/param->isAutoClosure());
if (resultTy) {
param->setDefaultValue(e);
}
tc.checkInitializerErrorHandling(initContext, e);
// Walk the checked initializer and contextualize any closures
// we saw there.
(void)tc.contextualizeInitializer(initContext, e);
}
}
PrecedenceGroupDecl *TypeChecker::lookupPrecedenceGroup(DeclContext *dc,
Identifier name,
SourceLoc nameLoc) {
auto *group = evaluateOrDefault(
dc->getASTContext().evaluator,
LookupPrecedenceGroupRequest({dc, name, nameLoc}), nullptr);
if (group)
validatePrecedenceGroup(group);
return group;
}
static NominalTypeDecl *resolveSingleNominalTypeDecl(
DeclContext *DC, SourceLoc loc, Identifier ident, ASTContext &Ctx,
TypeResolutionFlags flags = TypeResolutionFlags(0)) {
auto *TyR = new (Ctx) SimpleIdentTypeRepr(loc, ident);
TypeLoc typeLoc = TypeLoc(TyR);
TypeResolutionOptions options = TypeResolverContext::TypeAliasDecl;
options |= flags;
if (TypeChecker::validateType(Ctx, typeLoc,
TypeResolution::forInterface(DC), options))
return nullptr;
return typeLoc.getType()->getAnyNominal();
}
static bool checkDesignatedTypes(OperatorDecl *OD,
ArrayRef<Identifier> identifiers,
ArrayRef<SourceLoc> identifierLocs,
ASTContext &ctx) {
assert(identifiers.size() == identifierLocs.size());
SmallVector<NominalTypeDecl *, 1> designatedNominalTypes;
auto *DC = OD->getDeclContext();
for (auto index : indices(identifiers)) {
auto *decl = resolveSingleNominalTypeDecl(DC, identifierLocs[index],
identifiers[index], ctx);
if (!decl)
return true;
designatedNominalTypes.push_back(decl);
}
OD->setDesignatedNominalTypes(ctx.AllocateCopy(designatedNominalTypes));
return false;
}
/// Validate the given operator declaration.
///
/// This establishes key invariants, such as an InfixOperatorDecl's
/// reference to its precedence group and the transitive validity of that
/// group.
llvm::Expected<PrecedenceGroupDecl *>
OperatorPrecedenceGroupRequest::evaluate(Evaluator &evaluator,
InfixOperatorDecl *IOD) const {
auto enableOperatorDesignatedTypes =
IOD->getASTContext().LangOpts.EnableOperatorDesignatedTypes;
auto &Diags = IOD->getASTContext().Diags;
PrecedenceGroupDecl *group = nullptr;
auto identifiers = IOD->getIdentifiers();
auto identifierLocs = IOD->getIdentifierLocs();
if (!identifiers.empty()) {
group = TypeChecker::lookupPrecedenceGroup(
IOD->getDeclContext(), identifiers[0], identifierLocs[0]);
if (group) {
identifiers = identifiers.slice(1);
identifierLocs = identifierLocs.slice(1);
} else {
// If we're either not allowing types, or we are allowing them
// and this identifier is not a type, emit an error as if it's
// a precedence group.
auto *DC = IOD->getDeclContext();
if (!(enableOperatorDesignatedTypes &&
resolveSingleNominalTypeDecl(DC, identifierLocs[0], identifiers[0],
IOD->getASTContext(),
TypeResolutionFlags::SilenceErrors))) {
Diags.diagnose(identifierLocs[0], diag::unknown_precedence_group,
identifiers[0]);
identifiers = identifiers.slice(1);
identifierLocs = identifierLocs.slice(1);
}
}
}
if (!identifiers.empty() && !enableOperatorDesignatedTypes) {
assert(!group);
Diags.diagnose(identifierLocs[0], diag::unknown_precedence_group,
identifiers[0]);
identifiers = identifiers.slice(1);
identifierLocs = identifierLocs.slice(1);
assert(identifiers.empty() && identifierLocs.empty());
}
if (!group) {
group = TypeChecker::lookupPrecedenceGroup(
IOD->getDeclContext(), IOD->getASTContext().Id_DefaultPrecedence,
SourceLoc());
}
if (!group) {
Diags.diagnose(IOD->getLoc(), diag::missing_builtin_precedence_group,
IOD->getASTContext().Id_DefaultPrecedence);
}
auto nominalTypes = IOD->getDesignatedNominalTypes();
if (nominalTypes.empty() && enableOperatorDesignatedTypes) {
if (checkDesignatedTypes(IOD, identifiers, identifierLocs,
IOD->getASTContext())) {
IOD->setInvalid();
}
}
return group;
}
bool swift::doesContextHaveValueSemantics(DeclContext *dc) {
if (Type contextTy = dc->getDeclaredInterfaceType())
return !contextTy->hasReferenceSemantics();
return false;
}
llvm::Expected<SelfAccessKind>
SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
if (FD->getAttrs().getAttribute<MutatingAttr>(true)) {
if (!FD->isInstanceMember() ||
!doesContextHaveValueSemantics(FD->getDeclContext())) {
return SelfAccessKind::NonMutating;
}
return SelfAccessKind::Mutating;
} else if (FD->getAttrs().hasAttribute<NonMutatingAttr>()) {
return SelfAccessKind::NonMutating;
} else if (FD->getAttrs().hasAttribute<ConsumingAttr>()) {
return SelfAccessKind::Consuming;
}
if (auto *AD = dyn_cast<AccessorDecl>(FD)) {
// Non-static set/willSet/didSet/mutableAddress default to mutating.
// get/address default to non-mutating.
switch (AD->getAccessorKind()) {
case AccessorKind::Address:
case AccessorKind::Get:
case AccessorKind::Read:
break;
case AccessorKind::MutableAddress:
case AccessorKind::Set:
case AccessorKind::Modify:
if (AD->isInstanceMember() &&
doesContextHaveValueSemantics(AD->getDeclContext()))
return SelfAccessKind::Mutating;
break;
case AccessorKind::WillSet:
case AccessorKind::DidSet: {
auto *storage =AD->getStorage();
if (storage->isSetterMutating())
return SelfAccessKind::Mutating;
break;
}
}
}
return SelfAccessKind::NonMutating;
}
/// Check the requirements in the where clause of the given \c source
/// to ensure that they don't introduce additional 'Self' requirements.
static void checkProtocolSelfRequirements(ProtocolDecl *proto,
TypeDecl *source) {
WhereClauseOwner(source).visitRequirements(
TypeResolutionStage::Interface,
[&](const Requirement &req, RequirementRepr *reqRepr) {
switch (req.getKind()) {
case RequirementKind::Conformance:
case RequirementKind::Layout:
case RequirementKind::Superclass:
if (reqRepr &&
req.getFirstType()->isEqual(proto->getSelfInterfaceType())) {
auto &diags = proto->getASTContext().Diags;
diags.diagnose(reqRepr->getSubjectLoc().getLoc(),
diag::protocol_where_clause_self_requirement);
}
return false;
case RequirementKind::SameType:
return false;
}
llvm_unreachable("unhandled kind");
});
}
/// For now, DynamicSelfType can only appear at the top level of a
/// function result type, possibly wrapped in an optional type.
///
/// In the future, we could generalize it to allow it in any
/// covariant position, so that for example a class method could
/// return '() -> Self'.
static void checkDynamicSelfType(ValueDecl *decl, Type type) {
if (!type->hasDynamicSelfType())
return;
if (auto objectTy = type->getOptionalObjectType())
type = objectTy;
if (type->is<DynamicSelfType>())
return;
if (isa<FuncDecl>(decl))
decl->diagnose(diag::dynamic_self_invalid_method);
else if (isa<VarDecl>(decl))
decl->diagnose(diag::dynamic_self_invalid_property);
else {
assert(isa<SubscriptDecl>(decl));
decl->diagnose(diag::dynamic_self_invalid_subscript);
}
}
namespace {
class DeclChecker : public DeclVisitor<DeclChecker> {
public:
TypeChecker &TC;
explicit DeclChecker(TypeChecker &TC) : TC(TC) {}
void visit(Decl *decl) {
if (TC.Context.Stats)
TC.Context.Stats->getFrontendCounters().NumDeclsTypechecked++;
FrontendStatsTracer StatsTracer(TC.Context.Stats, "typecheck-decl", decl);
PrettyStackTraceDecl StackTrace("type-checking", decl);
DeclVisitor<DeclChecker>::visit(decl);
TC.checkUnsupportedProtocolType(decl);
if (auto VD = dyn_cast<ValueDecl>(decl)) {
auto &Context = TC.Context;
checkRedeclaration(Context, VD);
// Force some requests, which can produce diagnostics.
// Compute access level.
(void) VD->getFormalAccess();
// Compute overrides.
(void) VD->getOverriddenDecls();
// Check whether the member is @objc or dynamic.
(void) VD->isObjC();
(void) VD->isDynamic();
// If this is a member of a nominal type, don't allow it to have a name of
// "Type" or "Protocol" since we reserve the X.Type and X.Protocol
// expressions to mean something builtin to the language. We *do* allow
// these if they are escaped with backticks though.
if (VD->getDeclContext()->isTypeContext() &&
(VD->getFullName().isSimpleName(Context.Id_Type) ||
VD->getFullName().isSimpleName(Context.Id_Protocol)) &&
VD->getNameLoc().isValid() &&
Context.SourceMgr.extractText({VD->getNameLoc(), 1}) != "`") {
TC.diagnose(VD->getNameLoc(), diag::reserved_member_name,
VD->getFullName(), VD->getBaseName().getIdentifier().str());
TC.diagnose(VD->getNameLoc(), diag::backticks_to_escape)
.fixItReplace(VD->getNameLoc(),
"`" + VD->getBaseName().userFacingName().str() + "`");
}
}
}
//===--------------------------------------------------------------------===//
// Visit Methods.
//===--------------------------------------------------------------------===//
void visitGenericTypeParamDecl(GenericTypeParamDecl *D) {
llvm_unreachable("cannot reach here");
}
void visitImportDecl(ImportDecl *ID) {
TC.checkDeclAttributes(ID);
}
void visitOperatorDecl(OperatorDecl *OD) {
TC.checkDeclAttributes(OD);
auto &Ctx = OD->getASTContext();
if (auto *IOD = dyn_cast<InfixOperatorDecl>(OD)) {
(void)IOD->getPrecedenceGroup();
} else {
auto nominalTypes = OD->getDesignatedNominalTypes();
if (nominalTypes.empty() && Ctx.LangOpts.EnableOperatorDesignatedTypes) {
auto identifiers = OD->getIdentifiers();
auto identifierLocs = OD->getIdentifierLocs();
if (checkDesignatedTypes(OD, identifiers, identifierLocs, Ctx))
OD->setInvalid();
}
return;
}
checkAccessControl(TC, OD);
}
void visitPrecedenceGroupDecl(PrecedenceGroupDecl *PGD) {
TC.checkDeclAttributes(PGD);
validatePrecedenceGroup(PGD);
checkAccessControl(TC, PGD);
}
void visitMissingMemberDecl(MissingMemberDecl *MMD) {
llvm_unreachable("should always be type-checked already");
}
void visitBoundVariable(VarDecl *VD) {
// WARNING: Anything you put in this function will only be run when the
// VarDecl is fully type-checked within its own file. It will NOT be run
// when the VarDecl is merely used from another file.
TC.validateDecl(VD);
// Compute these requests in case they emit diagnostics.
(void) VD->isGetterMutating();
(void) VD->isSetterMutating();
(void) VD->getPropertyWrapperBackingProperty();
(void) VD->getImplInfo();
// Add the '@_hasStorage' attribute if this property is stored.
if (VD->hasStorage() && !VD->getAttrs().hasAttribute<HasStorageAttr>())
VD->getAttrs().add(new (TC.Context) HasStorageAttr(/*isImplicit=*/true));
// Reject cases where this is a variable that has storage but it isn't
// allowed.
if (VD->hasStorage()) {
// Note: Stored properties in protocols, enums, etc are diagnosed in
// finishStorageImplInfo().
// We haven't implemented type-level storage in some contexts.
if (VD->isStatic()) {
auto PBD = VD->getParentPatternBinding();
// Selector for unimplemented_static_var message.
enum : unsigned {
Misc,
GenericTypes,
Classes,
ProtocolExtensions
};
auto unimplementedStatic = [&](unsigned diagSel) {
auto staticLoc = PBD->getStaticLoc();
TC.diagnose(VD->getLoc(), diag::unimplemented_static_var,
diagSel, PBD->getStaticSpelling(),
diagSel == Classes)
.highlight(staticLoc);
};
auto DC = VD->getDeclContext();
// Stored type variables in a generic context need to logically
// occur once per instantiation, which we don't yet handle.
if (DC->getExtendedProtocolDecl()) {
unimplementedStatic(ProtocolExtensions);
} else if (DC->isGenericContext()
&& !DC->getGenericSignatureOfContext()->areAllParamsConcrete()) {
unimplementedStatic(GenericTypes);
} else if (DC->getSelfClassDecl()) {
auto StaticSpelling = PBD->getStaticSpelling();
if (StaticSpelling != StaticSpellingKind::KeywordStatic)
unimplementedStatic(Classes);
}
}
}
TC.checkDeclAttributes(VD);
if (!checkOverrides(VD)) {
// If a property has an override attribute but does not override
// anything, complain.
auto overridden = VD->getOverriddenDecl();
if (auto *OA = VD->getAttrs().getAttribute<OverrideAttr>()) {
if (!overridden) {
TC.diagnose(VD, diag::property_does_not_override)
.highlight(OA->getLocation());
OA->setInvalid();
}
}
}
if (VD->getDeclContext()->getSelfClassDecl()) {
checkDynamicSelfType(VD, VD->getValueInterfaceType());
if (VD->getValueInterfaceType()->hasDynamicSelfType()) {
if (VD->hasStorage())
VD->diagnose(diag::dynamic_self_in_stored_property);
else if (VD->isSettable(nullptr))
VD->diagnose(diag::dynamic_self_in_mutable_property);
}
}
// Under the Swift 3 inference rules, if we have @IBInspectable or
// @GKInspectable but did not infer @objc, warn that the attribute is
if (!VD->isObjC() && TC.Context.LangOpts.EnableSwift3ObjCInference) {
if (auto attr = VD->getAttrs().getAttribute<IBInspectableAttr>()) {
TC.diagnose(attr->getLocation(),
diag::attribute_meaningless_when_nonobjc,
attr->getAttrName())
.fixItRemove(attr->getRange());
}
if (auto attr = VD->getAttrs().getAttribute<GKInspectableAttr>()) {
TC.diagnose(attr->getLocation(),
diag::attribute_meaningless_when_nonobjc,
attr->getAttrName())
.fixItRemove(attr->getRange());
}
}
// Now check all the accessors.
VD->visitEmittedAccessors([&](AccessorDecl *accessor) {
visit(accessor);
});
}
void visitBoundVars(Pattern *P) {
P->forEachVariable([&] (VarDecl *VD) { this->visitBoundVariable(VD); });
}
void visitPatternBindingDecl(PatternBindingDecl *PBD) {
DeclContext *DC = PBD->getDeclContext();
// Check all the pattern/init pairs in the PBD.
validatePatternBindingEntries(TC, PBD);
TC.checkDeclAttributes(PBD);
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i) {
// Type check each VarDecl that this PatternBinding handles.
visitBoundVars(PBD->getPattern(i));
// If we have a type but no initializer, check whether the type is
// default-initializable. If so, do it.
if (PBD->getPattern(i)->hasType() &&
!PBD->isInitialized(i) &&
PBD->isDefaultInitializable(i) &&
PBD->getPattern(i)->hasStorage() &&
!PBD->getPattern(i)->getType()->hasError()) {
auto type = PBD->getPattern(i)->getType();
if (auto defaultInit = TC.buildDefaultInitializer(type)) {
// If we got a default initializer, install it and re-type-check it
// to make sure it is properly coerced to the pattern type.
PBD->setInit(i, defaultInit);
}
}
if (PBD->isInitialized(i)) {
// Add the attribute that preserves the "has an initializer" value across
// module generation, as required for TBDGen.
PBD->getPattern(i)->forEachVariable([&](VarDecl *VD) {
if (VD->hasStorage() &&
!VD->getAttrs().hasAttribute<HasInitialValueAttr>()) {
auto *attr = new (TC.Context) HasInitialValueAttr(
/*IsImplicit=*/true);
VD->getAttrs().add(attr);
}
});
}
}
bool isInSILMode = false;
if (auto sourceFile = DC->getParentSourceFile())
isInSILMode = sourceFile->Kind == SourceFileKind::SIL;
bool isTypeContext = DC->isTypeContext();
// If this is a declaration without an initializer, reject code if
// uninitialized vars are not allowed.
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i) {
auto entry = PBD->getPatternList()[i];
if (entry.isInitialized() || isInSILMode) continue;
entry.getPattern()->forEachVariable([&](VarDecl *var) {
// If the variable has no storage, it never needs an initializer.
if (!var->hasStorage())
return;
if (var->isInvalid() || PBD->isInvalid())
return;
auto markVarAndPBDInvalid = [PBD, var] {
PBD->setInvalid();
var->setInvalid();
if (!var->hasType())
var->markInvalid();
};
// Properties with an opaque return type need an initializer to
// determine their underlying type.
if (var->getOpaqueResultTypeDecl()) {
TC.diagnose(var->getLoc(), diag::opaque_type_var_no_init);
}
// Non-member observing properties need an initializer.
if (var->getWriteImpl() == WriteImplKind::StoredWithObservers &&
!isTypeContext) {
TC.diagnose(var->getLoc(), diag::observingprop_requires_initializer);
markVarAndPBDInvalid();
return;
}
// Static/class declarations require an initializer unless in a
// protocol.
if (var->isStatic() && !isa<ProtocolDecl>(DC)) {
// ...but don't enforce this for SIL or module interface files.
switch (DC->getParentSourceFile()->Kind) {
case SourceFileKind::Interface:
case SourceFileKind::SIL:
return;
case SourceFileKind::Main:
case SourceFileKind::REPL:
case SourceFileKind::Library:
break;
}
TC.diagnose(var->getLoc(), diag::static_requires_initializer,
var->getCorrectStaticSpelling());
markVarAndPBDInvalid();
return;
}
// Global variables require an initializer in normal source files.
if (DC->isModuleScopeContext()) {
switch (DC->getParentSourceFile()->Kind) {
case SourceFileKind::Main:
case SourceFileKind::REPL:
case SourceFileKind::Interface:
case SourceFileKind::SIL:
return;
case SourceFileKind::Library:
break;
}
TC.diagnose(var->getLoc(), diag::global_requires_initializer,
var->isLet());
markVarAndPBDInvalid();
return;
}
});
}
TC.checkDeclAttributes(PBD);
checkAccessControl(TC, PBD);
// If the initializers in the PBD aren't checked yet, do so now.
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i) {
if (!PBD->isInitialized(i))
continue;
if (!PBD->isInitializerChecked(i)) {
TC.typeCheckPatternBinding(PBD, i);
}
if (!PBD->isInvalid()) {
auto &entry = PBD->getPatternList()[i];
auto *init = PBD->getInit(i);
// If we're performing an binding to a weak or unowned variable from a
// constructor call, emit a warning that the instance will be immediately
// deallocated.
diagnoseUnownedImmediateDeallocation(TC, PBD->getPattern(i),
entry.getEqualLoc(),
init);
// If we entered an initializer context, contextualize any
// auto-closures we might have created.
// Note that we don't contextualize the initializer for a property
// with a wrapper, because the initializer will have been subsumed
// by the backing storage property.
if (!DC->isLocalContext() &&
!(PBD->getSingleVar() &&
PBD->getSingleVar()->hasAttachedPropertyWrapper())) {
auto *initContext = cast_or_null<PatternBindingInitializer>(
entry.getInitContext());
if (initContext) {
// Check safety of error-handling in the declaration, too.
TC.checkInitializerErrorHandling(initContext, init);
(void) TC.contextualizeInitializer(initContext, init);
}
}
}
}
}
void visitSubscriptDecl(SubscriptDecl *SD) {
// Force requests that can emit diagnostics.
(void) SD->getInterfaceType();
(void) SD->getGenericSignature();
if (!SD->isInvalid()) {
TC.checkReferencedGenericParams(SD);
checkGenericParams(SD->getGenericParams(), SD, TC);
TC.checkProtocolSelfRequirements(SD);
}
TC.checkDeclAttributes(SD);
checkAccessControl(TC, SD);
if (!checkOverrides(SD)) {
// If a subscript has an override attribute but does not override
// anything, complain.
if (auto *OA = SD->getAttrs().getAttribute<OverrideAttr>()) {
if (!SD->getOverriddenDecl()) {
TC.diagnose(SD, diag::subscript_does_not_override)
.highlight(OA->getLocation());
OA->setInvalid();
}
}
}
// Compute these requests in case they emit diagnostics.
(void) SD->isGetterMutating();
(void) SD->isSetterMutating();
(void) SD->getImplInfo();
TC.checkParameterAttributes(SD->getIndices());
checkDefaultArguments(TC, SD->getIndices(), SD);
if (SD->getDeclContext()->getSelfClassDecl()) {
checkDynamicSelfType(SD, SD->getValueInterfaceType());
if (SD->getValueInterfaceType()->hasDynamicSelfType() &&
SD->supportsMutation()) {
SD->diagnose(diag::dynamic_self_in_mutable_subscript);
}
}
// Now check all the accessors.
SD->visitEmittedAccessors([&](AccessorDecl *accessor) {
visit(accessor);
});
}
void visitTypeAliasDecl(TypeAliasDecl *TAD) {
// Force requests that can emit diagnostics.
(void) TAD->getGenericSignature();
(void) TAD->getUnderlyingType();
TC.checkDeclAttributes(TAD);
checkAccessControl(TC, TAD);
}
void visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) {
// Force requests that can emit diagnostics.
(void) OTD->getGenericSignature();
TC.checkDeclAttributes(OTD);
checkAccessControl(TC, OTD);
}
void visitAssociatedTypeDecl(AssociatedTypeDecl *AT) {
TC.checkDeclAttributes(AT);
checkInheritanceClause(AT);
auto *proto = AT->getProtocol();
checkProtocolSelfRequirements(proto, AT);
if (proto->isObjC()) {
TC.diagnose(AT->getLoc(),
diag::associated_type_objc,
AT->getName(),
proto->getName());
}
checkAccessControl(TC, AT);
// Trigger the checking for overridden declarations.
(void) AT->getOverriddenDecls();
auto defaultType = AT->getDefaultDefinitionType();
if (defaultType && !defaultType->hasError()) {
// associatedtype X = X is invalid
auto mentionsItself =
defaultType.findIf([&](Type defaultType) {
if (auto DMT = defaultType->getAs<DependentMemberType>()) {
return DMT->getAssocType() == AT;
}
return false;
});
if (mentionsItself) {
TC.diagnose(AT->getDefaultDefinitionTypeRepr()->getLoc(),
diag::recursive_decl_reference,
AT->getDescriptiveKind(), AT->getName());
AT->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type);
}
}
}
void checkUnsupportedNestedType(NominalTypeDecl *NTD) {
TC.diagnoseInlinableLocalType(NTD);
// We don't support protocols outside the top level of a file.
if (isa<ProtocolDecl>(NTD) &&
!NTD->getParent()->isModuleScopeContext()) {
TC.diagnose(NTD->getLoc(),
diag::unsupported_nested_protocol,
NTD->getName());
NTD->setInvalid();
return;
}
// We don't support nested types in generics yet.
if (NTD->isGenericContext()) {
auto DC = NTD->getDeclContext();
if (auto proto = DC->getSelfProtocolDecl()) {
if (DC->getExtendedProtocolDecl()) {
TC.diagnose(NTD->getLoc(),
diag::unsupported_type_nested_in_protocol_extension,
NTD->getName(),
proto->getName());
} else {
TC.diagnose(NTD->getLoc(),
diag::unsupported_type_nested_in_protocol,
NTD->getName(),
proto->getName());
}
}
if (DC->isLocalContext() && DC->isGenericContext()) {
// A local generic context is a generic function.
if (auto AFD = dyn_cast<AbstractFunctionDecl>(DC)) {
TC.diagnose(NTD->getLoc(),
diag::unsupported_type_nested_in_generic_function,
NTD->getName(),
AFD->getFullName());
} else {
TC.diagnose(NTD->getLoc(),
diag::unsupported_type_nested_in_generic_closure,
NTD->getName());
}
}
}
}
void visitEnumDecl(EnumDecl *ED) {
checkUnsupportedNestedType(ED);
// FIXME: Remove this once we clean up the mess involving raw values.
(void) ED->getInterfaceType();
checkGenericParams(ED->getGenericParams(), ED, TC);
{
// Check for circular inheritance of the raw type.
SmallVector<EnumDecl *, 8> path;
path.push_back(ED);
checkCircularity(TC, ED, diag::circular_enum_inheritance,
DescriptiveDeclKind::Enum, path);
}
for (Decl *member : ED->getMembers())
visit(member);
TC.checkDeclAttributes(ED);
checkInheritanceClause(ED);
checkAccessControl(TC, ED);
TC.checkPatternBindingCaptures(ED);
if (auto rawTy = ED->getRawType()) {
// The raw type must be one of the blessed literal convertible types.
if (!computeAutomaticEnumValueKind(ED)) {
TC.diagnose(ED->getInherited().front().getSourceRange().Start,
diag::raw_type_not_literal_convertible,
rawTy);
ED->getInherited().front().setInvalidType(TC.Context);
}
// We need at least one case to have a raw value.
if (ED->getAllElements().empty()) {
TC.diagnose(ED->getInherited().front().getSourceRange().Start,
diag::empty_enum_raw_type);
}
}
checkExplicitAvailability(ED);
TC.checkDeclCircularity(ED);
TC.ConformanceContexts.push_back(ED);
}
void visitStructDecl(StructDecl *SD) {
checkUnsupportedNestedType(SD);
checkGenericParams(SD->getGenericParams(), SD, TC);
// Force lowering of stored properties.
(void) SD->getStoredProperties();
TC.addImplicitConstructors(SD);
for (Decl *Member : SD->getMembers())
visit(Member);
TC.checkPatternBindingCaptures(SD);
TC.checkDeclAttributes(SD);
checkInheritanceClause(SD);
checkAccessControl(TC, SD);
checkExplicitAvailability(SD);
TC.checkDeclCircularity(SD);
TC.ConformanceContexts.push_back(SD);
}
/// Check whether the given properties can be @NSManaged in this class.
static bool propertiesCanBeNSManaged(ClassDecl *classDecl,
ArrayRef<VarDecl *> vars) {
// Check whether we have an Objective-C-defined class in our
// inheritance chain.
if (!classDecl->checkAncestry(AncestryFlags::ClangImported))
return false;
// If all of the variables are @objc, we can use @NSManaged.
for (auto var : vars) {
if (!var->isObjC())
return false;
}
// Okay, we can use @NSManaged.
return true;
}
/// Check that all stored properties have in-class initializers.
void checkRequiredInClassInits(ClassDecl *cd) {
ClassDecl *source = nullptr;
for (auto member : cd->getMembers()) {
auto pbd = dyn_cast<PatternBindingDecl>(member);
if (!pbd)
continue;
if (pbd->isStatic() || !pbd->hasStorage() ||
pbd->isDefaultInitializable() || pbd->isInvalid())
continue;
// The variables in this pattern have not been
// initialized. Diagnose the lack of initial value.
pbd->setInvalid();
SmallVector<VarDecl *, 4> vars;
for (auto entry : pbd->getPatternList())
entry.getPattern()->collectVariables(vars);
bool suggestNSManaged = propertiesCanBeNSManaged(cd, vars);
switch (vars.size()) {
case 0:
llvm_unreachable("should have been marked invalid");
case 1:
TC.diagnose(pbd->getLoc(), diag::missing_in_class_init_1,
vars[0]->getName(), suggestNSManaged);
break;
case 2:
TC.diagnose(pbd->getLoc(), diag::missing_in_class_init_2,
vars[0]->getName(), vars[1]->getName(), suggestNSManaged);
break;
case 3:
TC.diagnose(pbd->getLoc(), diag::missing_in_class_init_3plus,
vars[0]->getName(), vars[1]->getName(), vars[2]->getName(),
false, suggestNSManaged);
break;
default:
TC.diagnose(pbd->getLoc(), diag::missing_in_class_init_3plus,
vars[0]->getName(), vars[1]->getName(), vars[2]->getName(),
true, suggestNSManaged);
break;
}
// Figure out where this requirement came from.
if (!source) {
source = cd;
while (true) {
// If this class had the 'requires_stored_property_inits'
// attribute, diagnose here.
if (source->getAttrs().
hasAttribute<RequiresStoredPropertyInitsAttr>())
break;
// If the superclass doesn't require in-class initial
// values, the requirement was introduced at this point, so
// stop here.
auto superclass = source->getSuperclassDecl();
if (!superclass->requiresStoredPropertyInits())
break;
// Keep looking.
source = superclass;
}
}
// Add a note describing why we need an initializer.
TC.diagnose(source, diag::requires_stored_property_inits_here,
source->getDeclaredType(), cd == source, suggestNSManaged);
}
}
void visitClassDecl(ClassDecl *CD) {
checkUnsupportedNestedType(CD);
// Force creation of the generic signature.
(void) CD->getGenericSignature();
checkGenericParams(CD->getGenericParams(), CD, TC);
{
// Check for circular inheritance.
SmallVector<ClassDecl *, 8> path;
path.push_back(CD);
checkCircularity(TC, CD, diag::circular_class_inheritance,
DescriptiveDeclKind::Class, path);
}
// Force lowering of stored properties.
(void) CD->getStoredProperties();
// Force creation of an implicit destructor, if any.
(void) CD->getDestructor();
for (Decl *Member : CD->getEmittedMembers())
visit(Member);
TC.checkPatternBindingCaptures(CD);
// If this class requires all of its stored properties to have
// in-class initializers, diagnose this now.
if (CD->requiresStoredPropertyInits())
checkRequiredInClassInits(CD);
// Compute @objc for each superclass member, to catch selector
// conflicts resulting from unintended overrides.
//
// FIXME: This should be a request so we can measure how much work
// we're doing here.
CD->walkSuperclasses(
[&](ClassDecl *superclass) {
if (!superclass->getParentSourceFile())
return TypeWalker::Action::Stop;
for (auto *member : superclass->getMembers()) {
if (auto *vd = dyn_cast<ValueDecl>(member)) {
if (vd->isPotentiallyOverridable()) {
(void) vd->isObjC();
}
}
}
return TypeWalker::Action::Continue;
});
if (auto superclassTy = CD->getSuperclass()) {
ClassDecl *Super = superclassTy->getClassOrBoundGenericClass();
if (auto *SF = CD->getParentSourceFile()) {
if (auto *tracker = SF->getReferencedNameTracker()) {
bool isPrivate =
CD->getFormalAccess() <= AccessLevel::FilePrivate;
tracker->addUsedMember({Super, Identifier()}, !isPrivate);
}
}
bool isInvalidSuperclass = false;
if (Super->isFinal()) {
TC.diagnose(CD, diag::inheritance_from_final_class,
Super->getName());
// FIXME: should this really be skipping the rest of decl-checking?
return;
}
if (Super->hasClangNode() && Super->getGenericParams()
&& superclassTy->hasTypeParameter()) {
TC.diagnose(CD,
diag::inheritance_from_unspecialized_objc_generic_class,
Super->getName());
}
switch (Super->getForeignClassKind()) {
case ClassDecl::ForeignKind::Normal:
break;
case ClassDecl::ForeignKind::CFType:
TC.diagnose(CD, diag::inheritance_from_cf_class,
Super->getName());
isInvalidSuperclass = true;
break;
case ClassDecl::ForeignKind::RuntimeOnly:
TC.diagnose(CD, diag::inheritance_from_objc_runtime_visible_class,
Super->getName());
isInvalidSuperclass = true;
break;
}
if (!isInvalidSuperclass && Super->hasMissingVTableEntries() &&
!Super->isResilient(CD->getParentModule(),
ResilienceExpansion::Minimal)) {
auto *superFile = Super->getModuleScopeContext();
if (auto *serialized = dyn_cast<SerializedASTFile>(superFile)) {
if (serialized->getLanguageVersionBuiltWith() !=
TC.getLangOpts().EffectiveLanguageVersion) {
TC.diagnose(CD,
diag::inheritance_from_class_with_missing_vtable_entries_versioned,
Super->getName(),
serialized->getLanguageVersionBuiltWith(),
TC.getLangOpts().EffectiveLanguageVersion);
isInvalidSuperclass = true;
}
}
if (!isInvalidSuperclass) {
TC.diagnose(
CD, diag::inheritance_from_class_with_missing_vtable_entries,
Super->getName());
isInvalidSuperclass = true;
}
}
if (!TC.Context.isAccessControlDisabled()) {
// Require the superclass to be open if this is outside its
// defining module. But don't emit another diagnostic if we
// already complained about the class being inherently
// un-subclassable.
if (!isInvalidSuperclass &&
!Super->hasOpenAccess(CD->getDeclContext()) &&
Super->getModuleContext() != CD->getModuleContext()) {
TC.diagnose(CD, diag::superclass_not_open, superclassTy);
isInvalidSuperclass = true;
}
// Require superclasses to be open if the subclass is open.
// This is a restriction we can consider lifting in the future,
// e.g. to enable a "sealed" superclass whose subclasses are all
// of one of several alternatives.
if (!isInvalidSuperclass &&
CD->getFormalAccess() == AccessLevel::Open &&
Super->getFormalAccess() != AccessLevel::Open) {
TC.diagnose(CD, diag::superclass_of_open_not_open, superclassTy);
TC.diagnose(Super, diag::superclass_here);
}
}
}
TC.checkDeclAttributes(CD);
checkInheritanceClause(CD);
checkAccessControl(TC, CD);
checkExplicitAvailability(CD);
TC.checkDeclCircularity(CD);
TC.ConformanceContexts.push_back(CD);
}
void visitProtocolDecl(ProtocolDecl *PD) {
checkUnsupportedNestedType(PD);
auto *SF = PD->getParentSourceFile();
{
// Check for circular inheritance within the protocol.
SmallVector<ProtocolDecl *, 8> path;
path.push_back(PD);
checkCircularity(TC, PD, diag::circular_protocol_def,
DescriptiveDeclKind::Protocol, path);
if (SF) {
if (auto *tracker = SF->getReferencedNameTracker()) {
bool isNonPrivate =
(PD->getFormalAccess() > AccessLevel::FilePrivate);
for (auto *parentProto : PD->getInheritedProtocols())
tracker->addUsedMember({parentProto, Identifier()}, isNonPrivate);
}
}
}
// Check the members.
for (auto Member : PD->getMembers())
visit(Member);
TC.checkDeclAttributes(PD);
checkAccessControl(TC, PD);
checkInheritanceClause(PD);
TC.checkDeclCircularity(PD);
if (PD->isResilient())
if (!SF || SF->Kind != SourceFileKind::Interface)
TC.inferDefaultWitnesses(PD);
if (TC.Context.LangOpts.DebugGenericSignatures) {
auto requirementsSig =
GenericSignature::get({PD->getProtocolSelfType()},
PD->getRequirementSignature());
llvm::errs() << "Protocol requirement signature:\n";
PD->dumpRef(llvm::errs());
llvm::errs() << "\n";
llvm::errs() << "Requirement signature: ";
requirementsSig->print(llvm::errs());
llvm::errs() << "\n";
// Note: One cannot canonicalize a requirement signature, because
// requirement signatures are necessarily missing requirements.
llvm::errs() << "Canonical requirement signature: ";
auto canRequirementSig =
CanGenericSignature::getCanonical(requirementsSig->getGenericParams(),
requirementsSig->getRequirements(),
/*skipValidation=*/true);
canRequirementSig->print(llvm::errs());
llvm::errs() << "\n";
}
// Explicitly calculate this bit.
(void) PD->existentialTypeSupported();
// Explicity compute the requirement signature to detect errors.
(void) PD->getRequirementSignature();
checkExplicitAvailability(PD);
}
void visitVarDecl(VarDecl *VD) {
// Delay type-checking on VarDecls until we see the corresponding
// PatternBindingDecl.
}
/// Determine whether the given declaration requires a definition.
///
/// Only valid for declarations that can have definitions, i.e.,
/// functions, initializers, etc.
static bool requiresDefinition(Decl *decl) {
// Invalid, implicit, and Clang-imported declarations never
// require a definition.
if (decl->isInvalid() || decl->isImplicit() || decl->hasClangNode())
return false;
// Protocol requirements do not require definitions.
if (isa<ProtocolDecl>(decl->getDeclContext()))
return false;
// Functions can have _silgen_name, semantics, and NSManaged attributes.
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
if (func->getAttrs().hasAttribute<SILGenNameAttr>() ||
func->getAttrs().hasAttribute<SemanticsAttr>() ||
func->getAttrs().hasAttribute<NSManagedAttr>())
return false;
}
// Declarations in SIL and module interface files don't require
// definitions.
if (auto sourceFile = decl->getDeclContext()->getParentSourceFile()) {
switch (sourceFile->Kind) {
case SourceFileKind::SIL:
case SourceFileKind::Interface:
return false;
case SourceFileKind::Library:
case SourceFileKind::Main:
case SourceFileKind::REPL:
break;
}
}
// Everything else requires a definition.
return true;
}
bool shouldSkipBodyTypechecking(const AbstractFunctionDecl *AFD) {
// Make sure we're in the mode that's skipping function bodies.
if (!TC.canSkipNonInlinableBodies())
return false;
// Make sure there even _is_ a body that we can skip.
if (!AFD->getBodySourceRange().isValid())
return false;
// If we're gonna serialize the body, we can't skip it.
if (AFD->getResilienceExpansion() == ResilienceExpansion::Minimal)
return false;
return true;
}
void visitFuncDecl(FuncDecl *FD) {
// Force these requests in case they emit diagnostics.
(void) FD->getInterfaceType();
(void) FD->getOperatorDecl();
if (!FD->isInvalid()) {
checkGenericParams(FD->getGenericParams(), FD, TC);
TC.checkReferencedGenericParams(FD);
TC.checkProtocolSelfRequirements(FD);
}
checkAccessControl(TC, FD);
TC.checkParameterAttributes(FD->getParameters());
TC.checkDeclAttributes(FD);
if (!checkOverrides(FD)) {
// If a method has an 'override' keyword but does not
// override anything, complain.
if (auto *OA = FD->getAttrs().getAttribute<OverrideAttr>()) {
if (!FD->getOverriddenDecl()) {
TC.diagnose(FD, diag::method_does_not_override)
.highlight(OA->getLocation());
OA->setInvalid();
}
}
}
if (requiresDefinition(FD) && !FD->hasBody()) {
// Complain if we should have a body.
TC.diagnose(FD->getLoc(), diag::func_decl_without_brace);
} else if (FD->getDeclContext()->isLocalContext()) {
// Check local function bodies right away.
TC.typeCheckAbstractFunctionBody(FD);
} else if (shouldSkipBodyTypechecking(FD)) {
FD->setBodySkipped(FD->getBodySourceRange());
} else {
// Record the body.
TC.definedFunctions.push_back(FD);
}
checkExplicitAvailability(FD);
if (FD->getDeclContext()->getSelfClassDecl())
checkDynamicSelfType(FD, FD->getResultInterfaceType());
checkDefaultArguments(TC, FD->getParameters(), FD);
// Validate 'static'/'class' on functions in extensions.
auto StaticSpelling = FD->getStaticSpelling();
if (StaticSpelling != StaticSpellingKind::None &&
isa<ExtensionDecl>(FD->getDeclContext())) {
if (auto *NTD = FD->getDeclContext()->getSelfNominalTypeDecl()) {
if (!isa<ClassDecl>(NTD)) {
if (StaticSpelling == StaticSpellingKind::KeywordClass) {
FD->diagnose(diag::class_func_not_in_class, false)
.fixItReplace(FD->getStaticLoc(), "static");
NTD->diagnose(diag::extended_type_declared_here);
}
}
}
}
// Member functions need some special validation logic.
if (FD->getDeclContext()->isTypeContext()) {
if (FD->isOperator() && !isMemberOperator(FD, nullptr)) {
auto selfNominal = FD->getDeclContext()->getSelfNominalTypeDecl();
auto isProtocol = selfNominal && isa<ProtocolDecl>(selfNominal);
// We did not find 'Self'. Complain.
FD->diagnose(diag::operator_in_unrelated_type,
FD->getDeclContext()->getDeclaredInterfaceType(), isProtocol,
FD->getFullName());
}
}
// If the function is exported to C, it must be representable in (Obj-)C.
// FIXME: This needs to be moved to its own request if we want to
// productize @_cdecl.
if (auto CDeclAttr = FD->getAttrs().getAttribute<swift::CDeclAttr>()) {
Optional<ForeignErrorConvention> errorConvention;
if (isRepresentableInObjC(FD, ObjCReason::ExplicitlyCDecl,
errorConvention)) {
if (FD->hasThrows()) {
FD->setForeignErrorConvention(*errorConvention);
TC.diagnose(CDeclAttr->getLocation(), diag::cdecl_throws);
}
}
}
}
void visitModuleDecl(ModuleDecl *) { }
void visitEnumCaseDecl(EnumCaseDecl *ECD) {
// The type-checker doesn't care about how these are grouped.
}
void visitEnumElementDecl(EnumElementDecl *EED) {
(void) EED->getInterfaceType();
auto *ED = EED->getParentEnum();
TC.checkDeclAttributes(EED);
if (auto *PL = EED->getParameterList()) {
TC.checkParameterAttributes(PL);
checkDefaultArguments(TC, PL, EED);
}
// We don't yet support raw values on payload cases.
if (EED->hasAssociatedValues()) {
if (auto rawTy = ED->getRawType()) {
TC.diagnose(EED->getLoc(),
diag::enum_with_raw_type_case_with_argument);
TC.diagnose(ED->getInherited().front().getSourceRange().Start,
diag::enum_raw_type_here, rawTy);
EED->setInvalid();
}
}
// Force the raw value expr then yell if our parent doesn't have a raw type.
Expr *RVE = EED->getRawValueExpr();
if (RVE && !ED->hasRawType()) {
TC.diagnose(RVE->getLoc(), diag::enum_raw_value_without_raw_type);
EED->setInvalid();
}
checkAccessControl(TC, EED);
}
void visitExtensionDecl(ExtensionDecl *ED) {
// Produce any diagnostics for the extended type.
auto extType = ED->getExtendedType();
auto nominal = ED->computeExtendedNominal();
if (nominal == nullptr) {
const bool wasAlreadyInvalid = ED->isInvalid();
ED->setInvalid();
if (extType && !extType->hasError() && extType->getAnyNominal()) {
// If we've got here, then we have some kind of extension of a prima
// fascie non-nominal type. This can come up when we're projecting
// typealiases out of bound generic types.
//
// struct Array<T> { typealias Indices = Range<Int> }
// extension Array.Indices.Bound {}
//
// Offer to rewrite it to the underlying nominal type.
auto canExtType = extType->getCanonicalType();
ED->diagnose(diag::invalid_nominal_extension, extType, canExtType)
.highlight(ED->getExtendedTypeRepr()->getSourceRange());
ED->diagnose(diag::invalid_nominal_extension_rewrite, canExtType)
.fixItReplace(ED->getExtendedTypeRepr()->getSourceRange(),
canExtType->getString());
} else if (!wasAlreadyInvalid) {
// If nothing else applies, fall back to a generic diagnostic.
ED->diagnose(diag::non_nominal_extension, extType);
}
return;
}
// Produce any diagnostics for the generic signature.
(void) ED->getGenericSignature();
if (extType && !extType->hasError()) {
// The first condition catches syntactic forms like
// protocol A & B { ... } // may be protocols or typealiases
// The second condition also looks through typealiases and catches
// typealias T = P1 & P2 // P2 is a refined protocol of P1
// extension T { ... }
// However, it is trickier to catch cases like
// typealias T = P2 & P1 // P2 is a refined protocol of P1
// extension T { ... }
// so we don't do that here.
auto extTypeRepr = ED->getExtendedTypeRepr();
auto *extTypeNominal = extType->getAnyNominal();
bool firstNominalIsNotMostSpecific =
extTypeNominal && extTypeNominal != nominal;
if (isa<CompositionTypeRepr>(extTypeRepr)
|| firstNominalIsNotMostSpecific) {
auto firstNominalType = nominal->getDeclaredType();
auto diag = ED->diagnose(diag::composition_in_extended_type,
firstNominalType);
diag.highlight(extTypeRepr->getSourceRange());
if (firstNominalIsNotMostSpecific) {
diag.flush();
Type mostSpecificProtocol = extTypeNominal->getDeclaredType();
ED->diagnose(diag::composition_in_extended_type_alternative,
mostSpecificProtocol)
.fixItReplace(extTypeRepr->getSourceRange(),
mostSpecificProtocol->getString());
} else {
diag.fixItReplace(extTypeRepr->getSourceRange(),
firstNominalType->getString());
}
}
}
checkInheritanceClause(ED);
// Only generic and protocol types are permitted to have
// trailing where clauses.
if (auto trailingWhereClause = ED->getTrailingWhereClause()) {
if (!ED->getGenericParams() && !ED->isInvalid()) {
ED->diagnose(diag::extension_nongeneric_trailing_where,
nominal->getFullName())
.highlight(trailingWhereClause->getSourceRange());
}
}
checkGenericParams(ED->getGenericParams(), ED, TC);
for (Decl *Member : ED->getMembers())
visit(Member);
TC.ConformanceContexts.push_back(ED);
TC.checkDeclAttributes(ED);
checkAccessControl(TC, ED);
checkExplicitAvailability(ED);
}
void visitTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {
// See swift::performTypeChecking for TopLevelCodeDecl handling.
llvm_unreachable("TopLevelCodeDecls are handled elsewhere");
}
void visitIfConfigDecl(IfConfigDecl *ICD) {
// The active members of the #if block will be type checked along with
// their enclosing declaration.
TC.checkDeclAttributes(ICD);
}
void visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) {
if (PDD->hasBeenEmitted()) { return; }
PDD->markEmitted();
TC.diagnose(PDD->getMessage()->getStartLoc(),
PDD->isError() ? diag::pound_error : diag::pound_warning,
PDD->getMessage()->getValue())
.highlight(PDD->getMessage()->getSourceRange());
}
void visitConstructorDecl(ConstructorDecl *CD) {
(void) CD->getInterfaceType();
// Compute these requests in case they emit diagnostics.
(void) CD->getInitKind();
if (!CD->isInvalid()) {
checkGenericParams(CD->getGenericParams(), CD, TC);
TC.checkReferencedGenericParams(CD);
TC.checkProtocolSelfRequirements(CD);
}
TC.checkDeclAttributes(CD);
TC.checkParameterAttributes(CD->getParameters());
// Check whether this initializer overrides an initializer in its
// superclass.
if (!checkOverrides(CD)) {
// If an initializer has an override attribute but does not override
// anything or overrides something that doesn't need an 'override'
// keyword (e.g., a convenience initializer), complain.
// anything, or overrides something that complain.
if (auto *attr = CD->getAttrs().getAttribute<OverrideAttr>()) {
if (!CD->getOverriddenDecl()) {
TC.diagnose(CD, diag::initializer_does_not_override)
.highlight(attr->getLocation());
attr->setInvalid();
} else if (attr->isImplicit()) {
// Don't diagnose implicit attributes.
} else if (overrideRequiresKeyword(CD->getOverriddenDecl())
== OverrideRequiresKeyword::Never) {
// Special case: we are overriding a 'required' initializer, so we
// need (only) the 'required' keyword.
if (cast<ConstructorDecl>(CD->getOverriddenDecl())->isRequired()) {
if (CD->getAttrs().hasAttribute<RequiredAttr>()) {
TC.diagnose(CD, diag::required_initializer_override_keyword)
.fixItRemove(attr->getLocation());
} else {
TC.diagnose(CD, diag::required_initializer_override_wrong_keyword)
.fixItReplace(attr->getLocation(), "required");
CD->getAttrs().add(
new (TC.Context) RequiredAttr(/*IsImplicit=*/true));
}
TC.diagnose(findNonImplicitRequiredInit(CD->getOverriddenDecl()),
diag::overridden_required_initializer_here);
} else {
// We tried to override a convenience initializer.
TC.diagnose(CD, diag::initializer_does_not_override)
.highlight(attr->getLocation());
TC.diagnose(CD->getOverriddenDecl(),
diag::convenience_init_override_here);
}
}
}
// A failable initializer cannot override a non-failable one.
// This would normally be diagnosed by the covariance rules;
// however, those are disabled so that we can provide a more
// specific diagnostic here.
if (CD->isFailable() &&
CD->getOverriddenDecl() &&
!CD->getOverriddenDecl()->isFailable()) {
TC.diagnose(CD, diag::failable_initializer_override,
CD->getFullName());
TC.diagnose(CD->getOverriddenDecl(),
diag::nonfailable_initializer_override_here,
CD->getOverriddenDecl()->getFullName());
}
}
// If this initializer overrides a 'required' initializer, it must itself
// be marked 'required'.
if (!CD->getAttrs().hasAttribute<RequiredAttr>()) {
if (CD->getOverriddenDecl() && CD->getOverriddenDecl()->isRequired()) {
TC.diagnose(CD, diag::required_initializer_missing_keyword)
.fixItInsert(CD->getLoc(), "required ");
TC.diagnose(findNonImplicitRequiredInit(CD->getOverriddenDecl()),
diag::overridden_required_initializer_here);
CD->getAttrs().add(
new (TC.Context) RequiredAttr(/*IsImplicit=*/true));
}
}
if (CD->isRequired()) {
if (auto nominal = CD->getDeclContext()->getSelfNominalTypeDecl()) {
AccessLevel requiredAccess;
switch (nominal->getFormalAccess()) {
case AccessLevel::Open:
requiredAccess = AccessLevel::Public;
break;
case AccessLevel::Public:
case AccessLevel::Internal:
requiredAccess = AccessLevel::Internal;
break;
case AccessLevel::FilePrivate:
case AccessLevel::Private:
requiredAccess = AccessLevel::FilePrivate;
break;
}
if (CD->getFormalAccess() < requiredAccess) {
auto diag = TC.diagnose(CD, diag::required_initializer_not_accessible,
nominal->getFullName());
fixItAccess(diag, CD, requiredAccess);
}
}
}
checkAccessControl(TC, CD);
if (requiresDefinition(CD) && !CD->hasBody()) {
// Complain if we should have a body.
TC.diagnose(CD->getLoc(), diag::missing_initializer_def);
} else if (CD->getDeclContext()->isLocalContext()) {
// Check local function bodies right away.
TC.typeCheckAbstractFunctionBody(CD);
} else if (shouldSkipBodyTypechecking(CD)) {
CD->setBodySkipped(CD->getBodySourceRange());
} else {
TC.definedFunctions.push_back(CD);
}
checkDefaultArguments(TC, CD->getParameters(), CD);
}
void visitDestructorDecl(DestructorDecl *DD) {
TC.checkDeclAttributes(DD);
if (DD->getDeclContext()->isLocalContext()) {
// Check local function bodies right away.
TC.typeCheckAbstractFunctionBody(DD);
} else if (shouldSkipBodyTypechecking(DD)) {
DD->setBodySkipped(DD->getBodySourceRange());
} else {
TC.definedFunctions.push_back(DD);
}
}
};
} // end anonymous namespace
bool TypeChecker::isAvailabilitySafeForConformance(
ProtocolDecl *proto, ValueDecl *requirement, ValueDecl *witness,
DeclContext *dc, AvailabilityContext &requirementInfo) {
// We assume conformances in
// non-SourceFiles have already been checked for availability.
if (!dc->getParentSourceFile())
return true;
NominalTypeDecl *conformingDecl = dc->getSelfNominalTypeDecl();
assert(conformingDecl && "Must have conforming declaration");
// Make sure that any access of the witness through the protocol
// can only occur when the witness is available. That is, make sure that
// on every version where the conforming declaration is available, if the
// requirement is available then the witness is available as well.
// We do this by checking that (an over-approximation of) the intersection of
// the requirement's available range with both the conforming declaration's
// available range and the protocol's available range is fully contained in
// (an over-approximation of) the intersection of the witnesses's available
// range with both the conforming type's available range and the protocol
// declaration's available range.
AvailabilityContext witnessInfo =
AvailabilityInference::availableRange(witness, Context);
requirementInfo = AvailabilityInference::availableRange(requirement, Context);
AvailabilityContext infoForConformingDecl =
overApproximateAvailabilityAtLocation(conformingDecl->getLoc(),
conformingDecl);
// Constrain over-approximates intersection of version ranges.
witnessInfo.constrainWith(infoForConformingDecl);
requirementInfo.constrainWith(infoForConformingDecl);
AvailabilityContext infoForProtocolDecl =
overApproximateAvailabilityAtLocation(proto->getLoc(), proto);
witnessInfo.constrainWith(infoForProtocolDecl);
requirementInfo.constrainWith(infoForProtocolDecl);
return requirementInfo.isContainedIn(witnessInfo);
}
void TypeChecker::typeCheckDecl(Decl *D) {
checkForForbiddenPrefix(D);
DeclChecker(*this).visit(D);
}
// Returns 'nullptr' if this is the setter's 'newValue' parameter;
// otherwise, returns the corresponding parameter of the subscript
// declaration.
static ParamDecl *getOriginalParamFromAccessor(AbstractStorageDecl *storage,
AccessorDecl *accessor,
ParamDecl *param) {
auto *accessorParams = accessor->getParameters();
unsigned startIndex = 0;
switch (accessor->getAccessorKind()) {
case AccessorKind::DidSet:
case AccessorKind::WillSet:
case AccessorKind::Set:
if (param == accessorParams->get(0)) {
// This is the 'newValue' parameter.
return nullptr;
}
startIndex = 1;
break;
default:
startIndex = 0;
break;
}
// If the parameter is not the 'newValue' parameter to a setter, it
// must be a subscript index parameter (or we have an invalid AST).
auto *subscript = cast<SubscriptDecl>(storage);
auto *subscriptParams = subscript->getIndices();
auto where = llvm::find_if(*accessorParams,
[param](ParamDecl *other) {
return other == param;
});
assert(where != accessorParams->end());
unsigned index = where - accessorParams->begin();
return subscriptParams->get(index - startIndex);
}
llvm::Expected<bool>
IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator,
ValueDecl *decl) const {
TypeRepr *TyR = nullptr;
switch (decl->getKind()) {
case DeclKind::Func: {
TyR = cast<FuncDecl>(decl)->getBodyResultTypeLoc().getTypeRepr();
break;
}
case DeclKind::Accessor: {
auto *accessor = cast<AccessorDecl>(decl);
if (!accessor->isGetter())
break;
auto *storage = accessor->getStorage();
if (auto *subscript = dyn_cast<SubscriptDecl>(storage))
TyR = subscript->getElementTypeLoc().getTypeRepr();
else
TyR = cast<VarDecl>(storage)->getTypeRepr();
break;
}
case DeclKind::Subscript:
TyR = cast<SubscriptDecl>(decl)->getElementTypeLoc().getTypeRepr();
break;
case DeclKind::Param: {
auto *param = cast<ParamDecl>(decl);
if (param->isSelfParameter())
return false;
if (auto *accessor = dyn_cast<AccessorDecl>(param->getDeclContext())) {
auto *storage = accessor->getStorage();
auto *originalParam = getOriginalParamFromAccessor(
storage, accessor, param);
if (originalParam == nullptr) {
// This is the setter's newValue parameter.
return storage->isImplicitlyUnwrappedOptional();
}
if (param != originalParam) {
// This is the 'subscript(...) { get { ... } set { ... } }' case.
// This means we cloned the parameter list for each accessor.
// Delegate to the original parameter.
return originalParam->isImplicitlyUnwrappedOptional();
}
// This is the 'subscript(...) { <<body of getter>> }' case.
// The subscript and the getter share their ParamDecls.
// Fall through.
}
// Handle eg, 'inout Int!' or '__owned NSObject!'.
TyR = param->getTypeRepr();
if (auto *STR = dyn_cast_or_null<SpecifierTypeRepr>(TyR))
TyR = STR->getBase();
break;
}
case DeclKind::Var:
// FIXME: See the comment in validateTypedPattern().
break;
default:
break;
}
return (TyR && TyR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional);
}
/// Validate the underlying type of the given typealias.
llvm::Expected<Type>
UnderlyingTypeRequest::evaluate(Evaluator &evaluator,
TypeAliasDecl *typeAlias) const {
TypeResolutionOptions options((typeAlias->getGenericParams()
? TypeResolverContext::GenericTypeAliasDecl
: TypeResolverContext::TypeAliasDecl));
if (!typeAlias->getDeclContext()->isCascadingContextForLookup(
/*functionsAreNonCascading*/ true)) {
options |= TypeResolutionFlags::KnownNonCascadingDependency;
}
// This can happen when code completion is attempted inside
// of typealias underlying type e.g. `typealias F = () -> Int#^TOK^#`
auto *underlyingRepr = typeAlias->getUnderlyingTypeRepr();
if (!underlyingRepr) {
typeAlias->setInvalid();
return ErrorType::get(typeAlias->getASTContext());
}
auto underlyingLoc = TypeLoc(typeAlias->getUnderlyingTypeRepr());
if (TypeChecker::validateType(typeAlias->getASTContext(), underlyingLoc,
TypeResolution::forInterface(typeAlias),
options)) {
typeAlias->setInvalid();
return ErrorType::get(typeAlias->getASTContext());
}
return underlyingLoc.getType();
}
/// Bind the given function declaration, which declares an operator, to the corresponding operator declaration.
llvm::Expected<OperatorDecl *>
FunctionOperatorRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
auto &C = FD->getASTContext();
auto &diags = C.Diags;
auto operatorName = FD->getFullName().getBaseIdentifier();
// Check for static/final/class when we're in a type.
auto dc = FD->getDeclContext();
if (dc->isTypeContext()) {
if (auto classDecl = dc->getSelfClassDecl()) {
// For a class, we also need the function or class to be 'final'.
if (!classDecl->isFinal() && !FD->isFinal() &&
FD->getStaticLoc().isValid() &&
FD->getStaticSpelling() != StaticSpellingKind::KeywordStatic) {
FD->diagnose(diag::nonfinal_operator_in_class,
operatorName, dc->getDeclaredInterfaceType())
.fixItInsert(FD->getAttributeInsertionLoc(/*forModifier=*/true),
"final ");
FD->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
}
}
} else if (!dc->isModuleScopeContext()) {
FD->diagnose(diag::operator_in_local_scope);
}
OperatorDecl *op = nullptr;
SourceFile &SF = *FD->getDeclContext()->getParentSourceFile();
if (FD->isUnaryOperator()) {
if (FD->getAttrs().hasAttribute<PrefixAttr>()) {
op = SF.lookupPrefixOperator(operatorName,
FD->isCascadingContextForLookup(false),
FD->getLoc());
} else if (FD->getAttrs().hasAttribute<PostfixAttr>()) {
op = SF.lookupPostfixOperator(operatorName,
FD->isCascadingContextForLookup(false),
FD->getLoc());
} else {
auto prefixOp =
SF.lookupPrefixOperator(operatorName,
FD->isCascadingContextForLookup(false),
FD->getLoc());
auto postfixOp =
SF.lookupPostfixOperator(operatorName,
FD->isCascadingContextForLookup(false),
FD->getLoc());
// If we found both prefix and postfix, or neither prefix nor postfix,
// complain. We can't fix this situation.
if (static_cast<bool>(prefixOp) == static_cast<bool>(postfixOp)) {
diags.diagnose(FD, diag::declared_unary_op_without_attribute);
// If we found both, point at them.
if (prefixOp) {
diags.diagnose(prefixOp, diag::unary_operator_declaration_here, false)
.fixItInsert(FD->getLoc(), "prefix ");
diags.diagnose(postfixOp, diag::unary_operator_declaration_here, true)
.fixItInsert(FD->getLoc(), "postfix ");
} else {
// FIXME: Introduce a Fix-It that adds the operator declaration?
}
// FIXME: Errors could cascade here, because name lookup for this
// operator won't find this declaration.
return nullptr;
}
// We found only one operator declaration, so we know whether this
// should be a prefix or a postfix operator.
// Fix the AST and determine the insertion text.
const char *insertionText;
auto &C = FD->getASTContext();
if (postfixOp) {
insertionText = "postfix ";
op = postfixOp;
FD->getAttrs().add(new (C) PostfixAttr(/*implicit*/false));
} else {
insertionText = "prefix ";
op = prefixOp;
FD->getAttrs().add(new (C) PrefixAttr(/*implicit*/false));
}
// Emit diagnostic with the Fix-It.
diags.diagnose(FD->getFuncLoc(), diag::unary_op_missing_prepos_attribute,
static_cast<bool>(postfixOp))
.fixItInsert(FD->getFuncLoc(), insertionText);
diags.diagnose(op, diag::unary_operator_declaration_here,
static_cast<bool>(postfixOp));
}
} else if (FD->isBinaryOperator()) {
op = SF.lookupInfixOperator(operatorName,
FD->isCascadingContextForLookup(false),
FD->getLoc());
} else {
diags.diagnose(FD, diag::invalid_arg_count_for_operator);
return nullptr;
}
if (!op) {
SourceLoc insertionLoc;
if (isa<SourceFile>(FD->getParent())) {
// Parent context is SourceFile, insertion location is start of func
// declaration or unary operator
if (FD->isUnaryOperator()) {
insertionLoc = FD->getAttrs().getStartLoc();
} else {
insertionLoc = FD->getStartLoc();
}
} else {
// Find the topmost non-file decl context and insert there.
for (DeclContext *CurContext = FD->getLocalContext();
!isa<SourceFile>(CurContext);
CurContext = CurContext->getParent()) {
// Skip over non-decl contexts (e.g. closure expresssions)
if (auto *D = CurContext->getAsDecl())
insertionLoc = D->getStartLoc();
}
}
SmallString<128> insertion;
{
llvm::raw_svector_ostream str(insertion);
assert(FD->isUnaryOperator() || FD->isBinaryOperator());
if (FD->isUnaryOperator()) {
if (FD->getAttrs().hasAttribute<PrefixAttr>())
str << "prefix operator ";
else
str << "postfix operator ";
} else {
str << "infix operator ";
}
str << operatorName.str() << " : <# Precedence Group #>\n";
}
InFlightDiagnostic opDiagnostic =
diags.diagnose(FD, diag::declared_operator_without_operator_decl);
if (insertionLoc.isValid())
opDiagnostic.fixItInsert(insertionLoc, insertion);
return nullptr;
}
return op;
}
bool swift::isMemberOperator(FuncDecl *decl, Type type) {
// Check that member operators reference the type of 'Self'.
if (decl->isInvalid())
return true;
auto *DC = decl->getDeclContext();
auto selfNominal = DC->getSelfNominalTypeDecl();
// Check the parameters for a reference to 'Self'.
bool isProtocol = selfNominal && isa<ProtocolDecl>(selfNominal);
for (auto param : *decl->getParameters()) {
auto paramType = param->getInterfaceType();
if (!paramType) break;
// Look through a metatype reference, if there is one.
paramType = paramType->getMetatypeInstanceType();
auto nominal = paramType->getAnyNominal();
if (type.isNull()) {
// Is it the same nominal type?
if (selfNominal && nominal == selfNominal)
return true;
} else {
// Is it the same nominal type? Or a generic (which may or may not match)?
if (paramType->is<GenericTypeParamType>() ||
nominal == type->getAnyNominal())
return true;
}
if (isProtocol) {
// For a protocol, is it the 'Self' type parameter?
if (auto genericParam = paramType->getAs<GenericTypeParamType>())
if (genericParam->isEqual(DC->getSelfInterfaceType()))
return true;
}
}
return false;
}
static Type buildAddressorResultType(AccessorDecl *addressor,
Type valueType) {
assert(addressor->getAccessorKind() == AccessorKind::Address ||
addressor->getAccessorKind() == AccessorKind::MutableAddress);
PointerTypeKind pointerKind =
(addressor->getAccessorKind() == AccessorKind::Address)
? PTK_UnsafePointer
: PTK_UnsafeMutablePointer;
return valueType->wrapInPointer(pointerKind);
}
llvm::Expected<Type>
ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
auto &ctx = decl->getASTContext();
// Accessors always inherit their result type from their storage.
if (auto *accessor = dyn_cast<AccessorDecl>(decl)) {
auto *storage = accessor->getStorage();
switch (accessor->getAccessorKind()) {
// For getters, set the result type to the value type.
case AccessorKind::Get:
return storage->getValueInterfaceType();
// For setters and observers, set the old/new value parameter's type
// to the value type.
case AccessorKind::DidSet:
case AccessorKind::WillSet:
case AccessorKind::Set:
return TupleType::getEmpty(ctx);
// Addressor result types can get complicated because of the owner.
case AccessorKind::Address:
case AccessorKind::MutableAddress:
return buildAddressorResultType(accessor, storage->getValueInterfaceType());
// Coroutine accessors don't mention the value type directly.
// If we add yield types to the function type, we'll need to update this.
case AccessorKind::Read:
case AccessorKind::Modify:
return TupleType::getEmpty(ctx);
}
}
auto *resultTyRepr = getResultTypeLoc().getTypeRepr();
// Nothing to do if there's no result type.
if (resultTyRepr == nullptr)
return TupleType::getEmpty(ctx);
// Handle opaque types.
if (decl->getOpaqueResultTypeRepr()) {
auto *opaqueDecl = decl->getOpaqueResultTypeDecl();
return (opaqueDecl
? opaqueDecl->getDeclaredInterfaceType()
: ErrorType::get(ctx));
}
auto *dc = decl->getInnermostDeclContext();
auto resolution = TypeResolution::forInterface(dc);
return resolution.resolveType(
resultTyRepr, TypeResolverContext::FunctionResult);
}
llvm::Expected<ParamSpecifier>
ParamSpecifierRequest::evaluate(Evaluator &evaluator,
ParamDecl *param) const {
auto *dc = param->getDeclContext();
if (param->isSelfParameter()) {
auto selfParam = computeSelfParam(cast<AbstractFunctionDecl>(dc),
/*isInitializingCtor*/true,
/*wantDynamicSelf*/false);
return (selfParam.getParameterFlags().isInOut()
? ParamSpecifier::InOut
: ParamSpecifier::Default);
}
if (auto *accessor = dyn_cast<AccessorDecl>(dc)) {
auto *storage = accessor->getStorage();
auto *originalParam = getOriginalParamFromAccessor(
storage, accessor, param);
if (originalParam == nullptr) {
// This is the setter's newValue parameter. Note that even though
// the AST uses the 'Default' specifier, SIL will lower this to a
// +1 parameter.
return ParamSpecifier::Default;
}
if (param != originalParam) {
// This is the 'subscript(...) { get { ... } set { ... } }' case.
// This means we cloned the parameter list for each accessor.
// Delegate to the original parameter.
return originalParam->getSpecifier();
}
// This is the 'subscript(...) { <<body of getter>> }' case.
// The subscript and the getter share their ParamDecls.
// Fall through.
}
auto typeRepr = param->getTypeRepr();
assert(typeRepr != nullptr && "Should call setSpecifier() on "
"synthesized parameter declarations");
auto *nestedRepr = typeRepr;
// Look through parens here; other than parens, specifiers
// must appear at the top level of a parameter type.
while (auto *tupleRepr = dyn_cast<TupleTypeRepr>(nestedRepr)) {
if (!tupleRepr->isParenType())
break;
nestedRepr = tupleRepr->getElementType(0);
}
if (isa<InOutTypeRepr>(nestedRepr) &&
param->isDefaultArgument()) {
auto &ctx = param->getASTContext();
ctx.Diags.diagnose(param->getDefaultValue()->getLoc(),
swift::diag::cannot_provide_default_value_inout,
param->getName());
return ParamSpecifier::Default;
}
if (isa<InOutTypeRepr>(nestedRepr)) {
return ParamSpecifier::InOut;
} else if (isa<SharedTypeRepr>(nestedRepr)) {
return ParamSpecifier::Shared;
} else if (isa<OwnedTypeRepr>(nestedRepr)) {
return ParamSpecifier::Owned;
}
return ParamSpecifier::Default;
}
static Type validateParameterType(ParamDecl *decl) {
auto *dc = decl->getDeclContext();
auto resolution = TypeResolution::forInterface(dc);
TypeResolutionOptions options(None);
if (isa<AbstractClosureExpr>(dc)) {
options = TypeResolutionOptions(TypeResolverContext::ClosureExpr);
options |= TypeResolutionFlags::AllowUnspecifiedTypes;
options |= TypeResolutionFlags::AllowUnboundGenerics;
} else if (isa<AbstractFunctionDecl>(dc)) {
options = TypeResolutionOptions(TypeResolverContext::AbstractFunctionDecl);
} else if (isa<SubscriptDecl>(dc)) {
options = TypeResolutionOptions(TypeResolverContext::SubscriptDecl);
} else {
assert(isa<EnumElementDecl>(dc));
options = TypeResolutionOptions(TypeResolverContext::EnumElementDecl);
}
// If the element is a variadic parameter, resolve the parameter type as if
// it were in non-parameter position, since we want functions to be
// @escaping in this case.
options.setContext(decl->isVariadic() ?
TypeResolverContext::VariadicFunctionInput :
TypeResolverContext::FunctionInput);
options |= TypeResolutionFlags::Direct;
auto TL = TypeLoc(decl->getTypeRepr());
auto &ctx = dc->getASTContext();
if (TypeChecker::validateType(ctx, TL, resolution, options)) {
decl->setInvalid();
return ErrorType::get(ctx);
}
Type Ty = TL.getType();
if (decl->isVariadic()) {
Ty = TypeChecker::getArraySliceType(decl->getStartLoc(), Ty);
if (Ty.isNull()) {
decl->setInvalid();
return ErrorType::get(ctx);
}
// Disallow variadic parameters in enum elements.
if (options.getBaseContext() == TypeResolverContext::EnumElementDecl) {
decl->diagnose(diag::enum_element_ellipsis);
decl->setInvalid();
return ErrorType::get(ctx);
}
return Ty;
}
return TL.getType();
}
void TypeChecker::validateDecl(ValueDecl *D) {
// Handling validation failure due to re-entrancy is left
// up to the caller, who must call hasInterfaceType() to
// check that validateDecl() returned a fully-formed decl.
if (D->isBeingValidated() || D->hasInterfaceType())
return;
PrettyStackTraceDecl StackTrace("validating", D);
FrontendStatsTracer StatsTracer(Context.Stats, "validate-decl", D);
checkForForbiddenPrefix(D);
if (Context.Stats)
Context.Stats->getFrontendCounters().NumDeclsValidated++;
switch (D->getKind()) {
case DeclKind::Import:
case DeclKind::Extension:
case DeclKind::PatternBinding:
case DeclKind::EnumCase:
case DeclKind::TopLevelCode:
case DeclKind::InfixOperator:
case DeclKind::PrefixOperator:
case DeclKind::PostfixOperator:
case DeclKind::PrecedenceGroup:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
case DeclKind::MissingMember:
case DeclKind::Module:
case DeclKind::OpaqueType:
case DeclKind::GenericTypeParam:
llvm_unreachable("should not get here");
return;
case DeclKind::AssociatedType: {
auto assocType = cast<AssociatedTypeDecl>(D);
auto interfaceTy = assocType->getDeclaredInterfaceType();
assocType->setInterfaceType(MetatypeType::get(interfaceTy, Context));
break;
}
case DeclKind::TypeAlias: {
auto typeAlias = cast<TypeAliasDecl>(D);
auto genericSig = typeAlias->getGenericSignature();
SubstitutionMap subs;
if (genericSig)
subs = genericSig->getIdentitySubstitutionMap();
Type parent;
auto parentDC = typeAlias->getDeclContext();
if (parentDC->isTypeContext())
parent = parentDC->getSelfInterfaceType();
auto sugaredType = TypeAliasType::get(typeAlias, parent, subs,
typeAlias->getUnderlyingType());
typeAlias->setInterfaceType(MetatypeType::get(sugaredType, Context));
break;
}
case DeclKind::Enum:
case DeclKind::Struct:
case DeclKind::Class:
case DeclKind::Protocol: {
auto nominal = cast<NominalTypeDecl>(D);
Type declaredInterfaceTy = nominal->getDeclaredInterfaceType();
nominal->setInterfaceType(MetatypeType::get(declaredInterfaceTy, Context));
if (auto *ED = dyn_cast<EnumDecl>(nominal)) {
// @objc enums use their raw values as the value representation, so we
// need to force the values to be checked even in non-primaries.
//
// FIXME: This check can be removed once IRGen can be made tolerant of
// semantic failures post-Sema.
if (ED->isObjC()) {
(void)evaluateOrDefault(
Context.evaluator,
EnumRawValuesRequest{ED, TypeResolutionStage::Interface}, true);
}
}
break;
}
case DeclKind::Param: {
auto *PD = cast<ParamDecl>(D);
if (PD->isSelfParameter()) {
auto *AFD = cast<AbstractFunctionDecl>(PD->getDeclContext());
auto selfParam = computeSelfParam(AFD,
/*isInitializingCtor*/true,
/*wantDynamicSelf*/true);
PD->setInterfaceType(selfParam.getPlainType());
break;
}
if (auto *accessor = dyn_cast<AccessorDecl>(PD->getDeclContext())) {
auto *storage = accessor->getStorage();
auto *originalParam = getOriginalParamFromAccessor(
storage, accessor, PD);
if (originalParam == nullptr) {
auto type = storage->getValueInterfaceType();
PD->setInterfaceType(type);
break;
}
if (originalParam != PD) {
PD->setInterfaceType(originalParam->getInterfaceType());
break;
}
}
if (!PD->getTypeRepr())
return;
auto ty = validateParameterType(PD);
PD->setInterfaceType(ty);
break;
}
case DeclKind::Var: {
auto *VD = cast<VarDecl>(D);
auto *PBD = VD->getParentPatternBinding();
// Note that we need to handle the fact that some VarDecls don't
// have a PatternBindingDecl, for example the iterator in a
// 'for ... in ...' loop.
if (PBD == nullptr) {
VD->markInvalid();
break;
}
// If we're already checking our PatternBindingDecl, bail out
// without setting our own 'is being validated' flag, since we
// will attempt validation again later.
if (PBD->isBeingValidated())
return;
// Attempt to infer the type using initializer expressions.
validatePatternBindingEntries(*this, PBD);
// SWIFT_ENABLE_TENSORFLOW
// TODO(TF-789): Find proper way to type-check `@differentiable` attributes.
checkDeclDifferentiableAttributes(VD);
// SWIFT_ENABLE_TENSORFLOW END
auto parentPattern = VD->getParentPattern();
if (PBD->isInvalid() || !parentPattern->hasType()) {
parentPattern->setType(ErrorType::get(Context));
setBoundVarsTypeError(parentPattern, Context);
}
break;
}
case DeclKind::Func:
case DeclKind::Accessor:
case DeclKind::Constructor:
case DeclKind::Destructor: {
auto *AFD = cast<AbstractFunctionDecl>(D);
DeclValidationRAII IBV(AFD);
AFD->computeType();
// SWIFT_ENABLE_TENSORFLOW
// TODO(TF-789): Find proper way to type-check `@differentiable` attributes.
checkDeclDifferentiableAttributes(AFD);
// SWIFT_ENABLE_TENSORFLOW END
break;
}
case DeclKind::Subscript: {
auto *SD = cast<SubscriptDecl>(D);
DeclValidationRAII IBV(SD);
auto elementTy = SD->getElementInterfaceType();
SmallVector<AnyFunctionType::Param, 2> argTy;
SD->getIndices()->getParams(argTy);
Type funcTy;
if (auto sig = SD->getGenericSignature())
funcTy = GenericFunctionType::get(sig, argTy, elementTy);
else
funcTy = FunctionType::get(argTy, elementTy);
// Record the interface type.
SD->setInterfaceType(funcTy);
// SWIFT_ENABLE_TENSORFLOW
// TODO(TF-789): Find proper way to type-check `@differentiable` attributes.
checkDeclDifferentiableAttributes(SD);
// SWIFT_ENABLE_TENSORFLOW END
break;
}
case DeclKind::EnumElement: {
auto *EED = cast<EnumElementDecl>(D);
DeclValidationRAII IBV(EED);
auto *ED = EED->getParentEnum();
// The type of the enum element is either (Self.Type) -> Self
// or (Self.Type) -> (Args...) -> Self.
auto resultTy = ED->getDeclaredInterfaceType();
AnyFunctionType::Param selfTy(MetatypeType::get(resultTy, Context));
if (auto *PL = EED->getParameterList()) {
SmallVector<AnyFunctionType::Param, 4> argTy;
PL->getParams(argTy);
resultTy = FunctionType::get(argTy, resultTy);
}
if (auto genericSig = ED->getGenericSignature())
resultTy = GenericFunctionType::get(genericSig, {selfTy}, resultTy);
else
resultTy = FunctionType::get({selfTy}, resultTy);
// Record the interface type.
EED->setInterfaceType(resultTy);
break;
}
}
assert(D->hasInterfaceType());
}
llvm::Expected<DeclRange>
EmittedMembersRequest::evaluate(Evaluator &evaluator,
ClassDecl *CD) const {
if (!CD->getParentSourceFile())
return CD->getMembers();
auto &Context = CD->getASTContext();
// FIXME: Remove TypeChecker dependencies below
auto &TC = *(TypeChecker *) Context.getLazyResolver();
// We need to add implicit initializers because they
// affect vtable layout.
TC.addImplicitConstructors(CD);
auto forceConformance = [&](ProtocolDecl *protocol) {
if (auto ref = TypeChecker::conformsToProtocol(
CD->getDeclaredInterfaceType(), protocol, CD,
ConformanceCheckFlags::SkipConditionalRequirements,
SourceLoc())) {
auto conformance = ref->getConcrete();
if (conformance->getDeclContext() == CD &&
conformance->getState() == ProtocolConformanceState::Incomplete) {
TC.checkConformance(conformance->getRootNormalConformance());
}
}
};
// If the class is Encodable, Decodable or Hashable, force those
// conformances to ensure that the synthesized members appear in the vtable.
//
// FIXME: Generalize this to other protocols for which
// we can derive conformances.
forceConformance(Context.getProtocol(KnownProtocolKind::Decodable));
forceConformance(Context.getProtocol(KnownProtocolKind::Encodable));
forceConformance(Context.getProtocol(KnownProtocolKind::Hashable));
return CD->getMembers();
}
bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias,
Type underlyingType,
NominalTypeDecl *nominal) {
// Pass-through only makes sense when the typealias refers to a nominal
// type.
if (!nominal) return false;
// Check that the nominal type and the typealias are either both generic
// at this level or neither are.
if (nominal->isGeneric() != typealias->isGeneric())
return false;
// Make sure either both have generic signatures or neither do.
auto nominalSig = nominal->getGenericSignature();
auto typealiasSig = typealias->getGenericSignature();
if (static_cast<bool>(nominalSig) != static_cast<bool>(typealiasSig))
return false;
// If neither is generic, we're done: it's a pass-through alias.
if (!nominalSig) return true;
// Check that the type parameters are the same the whole way through.
auto nominalGenericParams = nominalSig->getGenericParams();
auto typealiasGenericParams = typealiasSig->getGenericParams();
if (nominalGenericParams.size() != typealiasGenericParams.size())
return false;
if (!std::equal(nominalGenericParams.begin(), nominalGenericParams.end(),
typealiasGenericParams.begin(),
[](GenericTypeParamType *gp1, GenericTypeParamType *gp2) {
return gp1->isEqual(gp2);
}))
return false;
// If neither is generic at this level, we have a pass-through typealias.
if (!typealias->isGeneric()) return true;
auto boundGenericType = underlyingType->getAs<BoundGenericType>();
if (!boundGenericType) return false;
// If our arguments line up with our innermost generic parameters, it's
// a passthrough typealias.
auto innermostGenericParams = typealiasSig->getInnermostGenericParams();
auto boundArgs = boundGenericType->getGenericArgs();
if (boundArgs.size() != innermostGenericParams.size())
return false;
return std::equal(boundArgs.begin(), boundArgs.end(),
innermostGenericParams.begin(),
[](Type arg, GenericTypeParamType *gp) {
return arg->isEqual(gp);
});
}
static bool isNonGenericTypeAliasType(Type type) {
// A non-generic typealias can extend a specialized type.
if (auto *aliasType = dyn_cast<TypeAliasType>(type.getPointer()))
return aliasType->getDecl()->getGenericContextDepth() == (unsigned)-1;
return false;
}
llvm::Expected<Type>
ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const {
auto error = [&ext]() {
ext->setInvalid();
return ErrorType::get(ext->getASTContext());
};
// If we didn't parse a type, fill in an error type and bail out.
auto *extendedRepr = ext->getExtendedTypeRepr();
if (!extendedRepr)
return error();
// Compute the extended type.
TypeResolutionOptions options(TypeResolverContext::ExtensionBinding);
options |= TypeResolutionFlags::AllowUnboundGenerics;
auto tr = TypeResolution::forStructural(ext->getDeclContext());
auto extendedType = tr.resolveType(extendedRepr, options);
if (extendedType->hasError())
return error();
// Hack to allow extending a generic typealias.
if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) {
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) {
// Nested Hack to break cycles if this is called before validation has
// finished.
if (aliasDecl->hasInterfaceType()) {
auto extendedNominal =
aliasDecl->getDeclaredInterfaceType()->getAnyNominal();
if (extendedNominal)
return TypeChecker::isPassThroughTypealias(
aliasDecl, aliasDecl->getUnderlyingType(), extendedNominal)
? extendedType
: extendedNominal->getDeclaredType();
} else {
if (auto ty = aliasDecl->getStructuralType()
->getAs<NominalOrBoundGenericNominalType>())
return TypeChecker::isPassThroughTypealias(aliasDecl, ty,
ty->getDecl())
? extendedType
: ty->getDecl()->getDeclaredType();
}
}
}
auto &diags = ext->getASTContext().Diags;
// Cannot extend a metatype.
if (extendedType->is<AnyMetatypeType>()) {
diags.diagnose(ext->getLoc(), diag::extension_metatype, extendedType)
.highlight(extendedRepr->getSourceRange());
return error();
}
// Cannot extend function types, tuple types, etc.
if (!extendedType->getAnyNominal()) {
diags.diagnose(ext->getLoc(), diag::non_nominal_extension, extendedType)
.highlight(extendedRepr->getSourceRange());
return error();
}
// Cannot extend a bound generic type, unless it's referenced via a
// non-generic typealias type.
if (extendedType->isSpecialized() &&
!isNonGenericTypeAliasType(extendedType)) {
diags.diagnose(ext->getLoc(), diag::extension_specialization,
extendedType->getAnyNominal()->getName())
.highlight(extendedRepr->getSourceRange());
return error();
}
return extendedType;
}
/// Build a default initializer string for the given pattern.
///
/// This string is suitable for display in diagnostics.
static Optional<std::string> buildDefaultInitializerString(TypeChecker &tc,
DeclContext *dc,
Pattern *pattern) {
switch (pattern->getKind()) {
#define REFUTABLE_PATTERN(Id, Parent) case PatternKind::Id:
#define PATTERN(Id, Parent)
#include "swift/AST/PatternNodes.def"
return None;
case PatternKind::Any:
return None;
case PatternKind::Named: {
if (!pattern->hasType())
return None;
// Special-case the various types we might see here.
auto type = pattern->getType();
// For literal-convertible types, form the corresponding literal.
#define CHECK_LITERAL_PROTOCOL(Kind, String) \
if (auto proto = tc.getProtocol(SourceLoc(), KnownProtocolKind::Kind)) { \
if (tc.conformsToProtocol(type, proto, dc, \
ConformanceCheckFlags::InExpression)) \
return std::string(String); \
}
CHECK_LITERAL_PROTOCOL(ExpressibleByArrayLiteral, "[]")
CHECK_LITERAL_PROTOCOL(ExpressibleByDictionaryLiteral, "[:]")
CHECK_LITERAL_PROTOCOL(ExpressibleByUnicodeScalarLiteral, "\"\"")
CHECK_LITERAL_PROTOCOL(ExpressibleByExtendedGraphemeClusterLiteral, "\"\"")
CHECK_LITERAL_PROTOCOL(ExpressibleByFloatLiteral, "0.0")
CHECK_LITERAL_PROTOCOL(ExpressibleByIntegerLiteral, "0")
CHECK_LITERAL_PROTOCOL(ExpressibleByStringLiteral, "\"\"")
#undef CHECK_LITERAL_PROTOCOL
// For optional types, use 'nil'.
if (type->getOptionalObjectType())
return std::string("nil");
return None;
}
case PatternKind::Paren: {
if (auto sub = buildDefaultInitializerString(
tc, dc, cast<ParenPattern>(pattern)->getSubPattern())) {
return "(" + *sub + ")";
}
return None;
}
case PatternKind::Tuple: {
std::string result = "(";
bool first = true;
for (auto elt : cast<TuplePattern>(pattern)->getElements()) {
if (auto sub = buildDefaultInitializerString(tc, dc, elt.getPattern())) {
if (first) {
first = false;
} else {
result += ", ";
}
result += *sub;
} else {
return None;
}
}
result += ")";
return result;
}
case PatternKind::Typed:
return buildDefaultInitializerString(
tc, dc, cast<TypedPattern>(pattern)->getSubPattern());
case PatternKind::Var:
return buildDefaultInitializerString(
tc, dc, cast<VarPattern>(pattern)->getSubPattern());
}
llvm_unreachable("Unhandled PatternKind in switch.");
}
/// Diagnose a class that does not have any initializers.
static void diagnoseClassWithoutInitializers(TypeChecker &tc,
ClassDecl *classDecl) {
tc.diagnose(classDecl, diag::class_without_init,
classDecl->getDeclaredType());
// HACK: We've got a special case to look out for and diagnose specifically to
// improve the experience of seeing this, and mitigate some confusion.
//
// For a class A which inherits from Decodable class B, class A may have
// additional members which prevent default initializer synthesis (and
// inheritance of other initializers). The user may have assumed that this
// case would synthesize Encodable/Decodable conformance for class A the same
// way it may have for class B, or other classes.
//
// It is helpful to suggest here that the user may have forgotten to override
// init(from:) (and encode(to:), if applicable) in a note, before we start
// listing the members that prevented initializer synthesis.
// TODO: Add a fixit along with this suggestion.
if (auto *superclassDecl = classDecl->getSuperclassDecl()) {
ASTContext &C = tc.Context;
auto *decodableProto = C.getProtocol(KnownProtocolKind::Decodable);
auto superclassType = superclassDecl->getDeclaredInterfaceType();
if (auto ref = TypeChecker::conformsToProtocol(superclassType, decodableProto,
superclassDecl,
ConformanceCheckOptions(),
SourceLoc())) {
// super conforms to Decodable, so we've failed to inherit init(from:).
// Let's suggest overriding it here.
//
// We're going to diagnose on the concrete init(from:) decl if it exists
// and isn't implicit; otherwise, on the subclass itself.
ValueDecl *diagDest = classDecl;
auto initFrom = DeclName(C, DeclBaseName::createConstructor(), C.Id_from);
auto result = tc.lookupMember(superclassDecl, superclassType, initFrom,
NameLookupFlags::ProtocolMembers |
NameLookupFlags::IgnoreAccessControl);
if (!result.empty() && !result.front().getValueDecl()->isImplicit())
diagDest = result.front().getValueDecl();
auto diagName = diag::decodable_suggest_overriding_init_here;
// This is also a bit of a hack, but the best place we've got at the
// moment to suggest this.
//
// If the superclass also conforms to Encodable, it's quite
// likely that the user forgot to override its encode(to:). In this case,
// we can produce a slightly different diagnostic to suggest doing so.
auto *encodableProto = C.getProtocol(KnownProtocolKind::Encodable);
if ((ref = tc.conformsToProtocol(superclassType, encodableProto,
superclassDecl,
ConformanceCheckOptions(),
SourceLoc()))) {
// We only want to produce this version of the diagnostic if the
// subclass doesn't directly implement encode(to:).
// The direct lookup here won't see an encode(to:) if it is inherited
// from the superclass.
auto encodeTo = DeclName(C, C.Id_encode, C.Id_to);
if (classDecl->lookupDirect(encodeTo).empty())
diagName = diag::codable_suggest_overriding_init_here;
}
tc.diagnose(diagDest, diagName);
}
}
// Lazily construct a mapping from backing storage properties to the
// declared properties.
bool computedBackingToOriginalVars = false;
llvm::SmallDenseMap<VarDecl *, VarDecl *> backingToOriginalVars;
auto getOriginalVar = [&](VarDecl *var) -> VarDecl * {
// If we haven't computed the mapping yet, do so now.
if (!computedBackingToOriginalVars) {
for (auto member : classDecl->getMembers()) {
if (auto var = dyn_cast<VarDecl>(member)) {
if (auto backingVar = var->getPropertyWrapperBackingProperty()) {
backingToOriginalVars[backingVar] = var;
}
}
}
computedBackingToOriginalVars = true;
}
auto known = backingToOriginalVars.find(var);
if (known == backingToOriginalVars.end())
return nullptr;
return known->second;
};
for (auto member : classDecl->getMembers()) {
auto pbd = dyn_cast<PatternBindingDecl>(member);
if (!pbd)
continue;
if (pbd->isStatic() || !pbd->hasStorage() ||
pbd->isDefaultInitializable() || pbd->isInvalid())
continue;
for (auto entry : pbd->getPatternList()) {
if (entry.isInitialized()) continue;
SmallVector<VarDecl *, 4> vars;
entry.getPattern()->collectVariables(vars);
if (vars.empty()) continue;
// Replace the variables we found with the originals for diagnostic
// purposes.
for (auto &var : vars) {
if (auto originalVar = getOriginalVar(var))
var = originalVar;
}
auto varLoc = vars[0]->getLoc();
Optional<InFlightDiagnostic> diag;
switch (vars.size()) {
case 1:
diag.emplace(tc.diagnose(varLoc, diag::note_no_in_class_init_1,
vars[0]->getName()));
break;
case 2:
diag.emplace(tc.diagnose(varLoc, diag::note_no_in_class_init_2,
vars[0]->getName(), vars[1]->getName()));
break;
case 3:
diag.emplace(tc.diagnose(varLoc, diag::note_no_in_class_init_3plus,
vars[0]->getName(), vars[1]->getName(),
vars[2]->getName(), false));
break;
default:
diag.emplace(tc.diagnose(varLoc, diag::note_no_in_class_init_3plus,
vars[0]->getName(), vars[1]->getName(),
vars[2]->getName(), true));
break;
}
if (auto defaultValueSuggestion
= buildDefaultInitializerString(tc, classDecl, entry.getPattern()))
diag->fixItInsertAfter(entry.getPattern()->getEndLoc(),
" = " + *defaultValueSuggestion);
}
}
}
void TypeChecker::maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl) {
if (auto *SF = classDecl->getParentSourceFile()) {
// Allow classes without initializers in SIL and module interface files.
switch (SF->Kind) {
case SourceFileKind::SIL:
case SourceFileKind::Interface:
return;
case SourceFileKind::Library:
case SourceFileKind::Main:
case SourceFileKind::REPL:
break;
}
}
// Some heuristics to skip emitting a diagnostic if the class is already
// irreperably busted.
if (classDecl->isInvalid() ||
classDecl->inheritsSuperclassInitializers())
return;
auto *superclassDecl = classDecl->getSuperclassDecl();
if (superclassDecl &&
superclassDecl->hasMissingDesignatedInitializers())
return;
for (auto member : classDecl->lookupDirect(DeclBaseName::createConstructor())) {
auto ctor = dyn_cast<ConstructorDecl>(member);
if (ctor && ctor->isDesignatedInit())
return;
}
diagnoseClassWithoutInitializers(*this, classDecl);
}