blob: 3bede6114df69997b0e3fcb11493d5bbc39a221e [file] [log] [blame]
//===--- TypeCheckOverride.cpp - Override Checking ------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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 declaration overrides.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "CodeSynthesis.h"
#include "MiscDiagnostics.h"
#include "TypeCheckAvailability.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/Availability.h"
#include "swift/AST/Decl.h"
#include "swift/AST/ParameterList.h"
using namespace swift;
static void adjustFunctionTypeForOverride(Type &type) {
// Drop 'throws'.
// FIXME: Do we want to allow overriding a function returning a value
// with one returning Never?
auto fnType = type->castTo<AnyFunctionType>();
auto extInfo = fnType->getExtInfo();
extInfo = extInfo.withThrows(false);
if (fnType->getExtInfo() != extInfo)
type = fnType->withExtInfo(extInfo);
}
/// Drop the optionality of the result type of the given function type.
static Type dropResultOptionality(Type type, unsigned uncurryLevel) {
// We've hit the result type.
if (uncurryLevel == 0) {
if (auto objectTy = type->getOptionalObjectType())
return objectTy;
return type;
}
// Determine the input and result types of this function.
auto fnType = type->castTo<AnyFunctionType>();
auto parameters = fnType->getParams();
Type resultType =
dropResultOptionality(fnType->getResult(), uncurryLevel - 1);
// Produce the resulting function type.
if (auto genericFn = dyn_cast<GenericFunctionType>(fnType)) {
return GenericFunctionType::get(genericFn->getGenericSignature(),
parameters, resultType,
fnType->getExtInfo());
}
return FunctionType::get(parameters, resultType, fnType->getExtInfo());
}
Type swift::getMemberTypeForComparison(ASTContext &ctx, ValueDecl *member,
ValueDecl *derivedDecl,
bool stripLabels) {
auto *method = dyn_cast<AbstractFunctionDecl>(member);
ConstructorDecl *ctor = nullptr;
if (method)
ctor = dyn_cast<ConstructorDecl>(method);
auto abstractStorage = dyn_cast<AbstractStorageDecl>(member);
assert((method || abstractStorage) && "Not a method or abstractStorage?");
SubscriptDecl *subscript = dyn_cast_or_null<SubscriptDecl>(abstractStorage);
if (!member->hasInterfaceType()) {
auto lazyResolver = ctx.getLazyResolver();
assert(lazyResolver && "Need to resolve interface type");
lazyResolver->resolveDeclSignature(member);
}
auto memberType = member->getInterfaceType();
if (derivedDecl) {
auto *dc = derivedDecl->getDeclContext();
auto owningType = dc->getDeclaredInterfaceType();
assert(owningType);
if (!derivedDecl->hasInterfaceType()) {
auto lazyResolver = ctx.getLazyResolver();
assert(lazyResolver && "Need to resolve interface type");
lazyResolver->resolveDeclSignature(derivedDecl);
}
memberType = owningType->adjustSuperclassMemberDeclType(member, derivedDecl,
memberType);
if (memberType->hasError())
return memberType;
}
if (stripLabels)
memberType = memberType->getUnlabeledType(ctx);
if (method) {
// For methods, strip off the 'Self' type.
memberType = memberType->castTo<AnyFunctionType>()->getResult();
adjustFunctionTypeForOverride(memberType);
} else if (subscript) {
// For subscripts, we don't have a 'Self' type, but turn it
// into a monomorphic function type.
auto funcTy = memberType->castTo<AnyFunctionType>();
memberType = FunctionType::get(funcTy->getParams(), funcTy->getResult(),
FunctionType::ExtInfo());
} else {
// For properties, strip off ownership.
memberType = memberType->getReferenceStorageReferent();
}
// Ignore the optionality of initializers when comparing types;
// we'll enforce this separately
if (ctor) {
memberType = dropResultOptionality(memberType, 1);
}
return memberType;
}
bool swift::isOverrideBasedOnType(ValueDecl *decl, Type declTy,
ValueDecl *parentDecl, Type parentDeclTy) {
auto *genericSig =
decl->getInnermostDeclContext()->getGenericSignatureOfContext();
auto canDeclTy = declTy->getCanonicalType(genericSig);
auto canParentDeclTy = parentDeclTy->getCanonicalType(genericSig);
auto declIUOAttr =
decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
auto parentDeclIUOAttr =
parentDecl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
if (declIUOAttr != parentDeclIUOAttr)
return false;
// If this is a constructor, let's compare only parameter types.
if (isa<ConstructorDecl>(decl)) {
auto fnType1 = declTy->castTo<AnyFunctionType>();
auto fnType2 = parentDeclTy->castTo<AnyFunctionType>();
return AnyFunctionType::equalParams(fnType1->getParams(),
fnType2->getParams());
}
return canDeclTy == canParentDeclTy;
}
/// Perform basic checking to determine whether a declaration can override a
/// declaration in a superclass.
static bool areOverrideCompatibleSimple(ValueDecl *decl,
ValueDecl *parentDecl) {
// If the number of argument labels does not match, these overrides cannot
// be compatible.
if (decl->getFullName().getArgumentNames().size() !=
parentDecl->getFullName().getArgumentNames().size())
return false;
// If the parent declaration is not in a class (or extension thereof), we
// cannot override it.
if (!parentDecl->getDeclContext()->getAsClassOrClassExtensionContext())
return false;
// The declarations must be of the same kind.
if (decl->getKind() != parentDecl->getKind())
return false;
// Ignore invalid parent declarations.
// FIXME: Do we really need this?
if (parentDecl->isInvalid())
return false;
if (auto func = dyn_cast<FuncDecl>(decl)) {
// Specific checking for methods.
auto parentFunc = cast<FuncDecl>(parentDecl);
if (func->isStatic() != parentFunc->isStatic())
return false;
if (func->isGeneric() != parentFunc->isGeneric())
return false;
} else if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
auto parentCtor = cast<ConstructorDecl>(parentDecl);
if (ctor->isGeneric() != parentCtor->isGeneric())
return false;
// Factory initializers cannot be overridden.
if (parentCtor->isFactoryInit())
return false;
} else if (auto var = dyn_cast<VarDecl>(decl)) {
auto parentVar = cast<VarDecl>(parentDecl);
if (var->isStatic() != parentVar->isStatic())
return false;
} else if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
auto parentSubscript = cast<SubscriptDecl>(parentDecl);
if (subscript->isGeneric() != parentSubscript->isGeneric())
return false;
}
return true;
}
static bool
diagnoseMismatchedOptionals(const ValueDecl *member,
const ParameterList *params, TypeLoc resultTL,
const ValueDecl *parentMember,
const ParameterList *parentParams, Type owningTy,
bool treatIUOResultAsError) {
auto &diags = member->getASTContext().Diags;
bool emittedError = false;
Type plainParentTy = owningTy->adjustSuperclassMemberDeclType(
parentMember, member, parentMember->getInterfaceType());
const auto *parentTy = plainParentTy->castTo<FunctionType>();
if (isa<AbstractFunctionDecl>(parentMember))
parentTy = parentTy->getResult()->castTo<FunctionType>();
// Check the parameter types.
auto checkParam = [&](const ParamDecl *decl, const ParamDecl *parentDecl) {
Type paramTy = decl->getType();
Type parentParamTy = parentDecl->getType();
if (!paramTy || !parentParamTy)
return;
TypeLoc TL = decl->getTypeLoc();
if (!TL.getTypeRepr())
return;
bool paramIsOptional = (bool) paramTy->getOptionalObjectType();
bool parentIsOptional = (bool) parentParamTy->getOptionalObjectType();
if (paramIsOptional == parentIsOptional)
return;
if (!paramIsOptional) {
if (parentDecl->getAttrs()
.hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
if (!treatIUOResultAsError)
return;
emittedError = true;
auto diag = diags.diagnose(decl->getStartLoc(),
diag::override_optional_mismatch,
member->getDescriptiveKind(),
isa<SubscriptDecl>(member),
parentParamTy, paramTy);
if (TL.getTypeRepr()->isSimple()) {
diag.fixItInsertAfter(TL.getSourceRange().End, "?");
} else {
diag.fixItInsert(TL.getSourceRange().Start, "(");
diag.fixItInsertAfter(TL.getSourceRange().End, ")?");
}
return;
}
if (!decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
return;
// Allow silencing this warning using parens.
if (TL.getType()->hasParenSugar())
return;
diags.diagnose(decl->getStartLoc(), diag::override_unnecessary_IUO,
member->getDescriptiveKind(), parentParamTy, paramTy)
.highlight(TL.getSourceRange());
auto sugaredForm =
dyn_cast<ImplicitlyUnwrappedOptionalTypeRepr>(TL.getTypeRepr());
if (sugaredForm) {
diags.diagnose(sugaredForm->getExclamationLoc(),
diag::override_unnecessary_IUO_remove)
.fixItRemove(sugaredForm->getExclamationLoc());
}
diags.diagnose(TL.getSourceRange().Start,
diag::override_unnecessary_IUO_silence)
.fixItInsert(TL.getSourceRange().Start, "(")
.fixItInsertAfter(TL.getSourceRange().End, ")");
};
// FIXME: If we ever allow argument reordering, this is incorrect.
ArrayRef<ParamDecl *> sharedParams = params->getArray();
ArrayRef<ParamDecl *> sharedParentParams = parentParams->getArray();
assert(sharedParams.size() == sharedParentParams.size());
for_each(sharedParams, sharedParentParams, checkParam);
if (!resultTL.getTypeRepr())
return emittedError;
auto checkResult = [&](TypeLoc resultTL, Type parentResultTy) {
Type resultTy = resultTL.getType();
if (!resultTy || !parentResultTy)
return;
if (!resultTy->getOptionalObjectType())
return;
TypeRepr *TR = resultTL.getTypeRepr();
bool resultIsPlainOptional = true;
if (member->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
resultIsPlainOptional = false;
if (resultIsPlainOptional || treatIUOResultAsError) {
if (parentResultTy->getOptionalObjectType())
return;
emittedError = true;
auto diag = diags.diagnose(resultTL.getSourceRange().Start,
diag::override_optional_result_mismatch,
member->getDescriptiveKind(),
isa<SubscriptDecl>(member),
parentResultTy, resultTy);
if (auto optForm = dyn_cast<OptionalTypeRepr>(TR)) {
diag.fixItRemove(optForm->getQuestionLoc());
} else if (auto iuoForm =
dyn_cast<ImplicitlyUnwrappedOptionalTypeRepr>(TR)) {
diag.fixItRemove(iuoForm->getExclamationLoc());
}
return;
}
if (!parentResultTy->getOptionalObjectType())
return;
// Allow silencing this warning using parens.
if (resultTy->hasParenSugar())
return;
diags.diagnose(resultTL.getSourceRange().Start,
diag::override_unnecessary_result_IUO,
member->getDescriptiveKind(), parentResultTy, resultTy)
.highlight(resultTL.getSourceRange());
auto sugaredForm = dyn_cast<ImplicitlyUnwrappedOptionalTypeRepr>(TR);
if (sugaredForm) {
diags.diagnose(sugaredForm->getExclamationLoc(),
diag::override_unnecessary_IUO_use_strict)
.fixItReplace(sugaredForm->getExclamationLoc(), "?");
}
diags.diagnose(resultTL.getSourceRange().Start,
diag::override_unnecessary_IUO_silence)
.fixItInsert(resultTL.getSourceRange().Start, "(")
.fixItInsertAfter(resultTL.getSourceRange().End, ")");
};
checkResult(resultTL, parentTy->getResult());
return emittedError;
}
/// Record that the \c overriding declarations overrides the
/// \c overridden declaration.
///
/// \returns true if an error occurred.
static bool recordOverride(TypeChecker &TC, ValueDecl *override,
ValueDecl *base, bool isKnownObjC = false);
/// If the difference between the types of \p decl and \p base is something
/// we feel confident about fixing (even partially), emit a note with fix-its
/// attached. Otherwise, no note will be emitted.
///
/// \returns true iff a diagnostic was emitted.
static bool noteFixableMismatchedTypes(ValueDecl *decl, const ValueDecl *base) {
auto &ctx = decl->getASTContext();
auto &diags = ctx.Diags;
DiagnosticTransaction tentativeDiags(diags);
{
Type baseTy = base->getInterfaceType();
if (baseTy->hasError())
return false;
Optional<InFlightDiagnostic> activeDiag;
if (auto *baseInit = dyn_cast<ConstructorDecl>(base)) {
// Special-case initializers, whose "type" isn't useful besides the
// input arguments.
auto *fnType = baseTy->getAs<AnyFunctionType>();
baseTy = fnType->getResult();
Type argTy = FunctionType::composeInput(ctx,
baseTy->getAs<AnyFunctionType>()
->getParams(),
false);
auto diagKind = diag::override_type_mismatch_with_fixits_init;
unsigned numArgs = baseInit->getParameters()->size();
activeDiag.emplace(diags.diagnose(decl, diagKind,
/*plural*/std::min(numArgs, 2U),
argTy));
} else {
if (isa<AbstractFunctionDecl>(base))
baseTy = baseTy->getAs<AnyFunctionType>()->getResult();
activeDiag.emplace(
diags.diagnose(decl,
diag::override_type_mismatch_with_fixits,
base->getDescriptiveKind(), baseTy));
}
if (fixItOverrideDeclarationTypes(*activeDiag, decl, base))
return true;
}
// There weren't any fixes we knew how to make. Drop this diagnostic.
tentativeDiags.abort();
return false;
}
namespace {
enum class OverrideCheckingAttempt {
PerfectMatch,
MismatchedOptional,
MismatchedTypes,
BaseName,
BaseNameWithMismatchedOptional,
Final
};
OverrideCheckingAttempt &operator++(OverrideCheckingAttempt &attempt) {
assert(attempt != OverrideCheckingAttempt::Final);
attempt = static_cast<OverrideCheckingAttempt>(1+static_cast<int>(attempt));
return attempt;
}
struct OverrideMatch {
ValueDecl *Decl;
bool IsExact;
Type SubstType;
};
}
static void diagnoseGeneralOverrideFailure(ValueDecl *decl,
ArrayRef<OverrideMatch> matches,
OverrideCheckingAttempt attempt) {
auto &diags = decl->getASTContext().Diags;
switch (attempt) {
case OverrideCheckingAttempt::PerfectMatch:
diags.diagnose(decl, diag::override_multiple_decls_base,
decl->getFullName());
break;
case OverrideCheckingAttempt::BaseName:
diags.diagnose(decl, diag::override_multiple_decls_arg_mismatch,
decl->getFullName());
break;
case OverrideCheckingAttempt::MismatchedOptional:
case OverrideCheckingAttempt::MismatchedTypes:
case OverrideCheckingAttempt::BaseNameWithMismatchedOptional:
if (isa<ConstructorDecl>(decl))
diags.diagnose(decl, diag::initializer_does_not_override);
else if (isa<SubscriptDecl>(decl))
diags.diagnose(decl, diag::subscript_does_not_override);
else if (isa<VarDecl>(decl))
diags.diagnose(decl, diag::property_does_not_override);
else
diags.diagnose(decl, diag::method_does_not_override);
break;
case OverrideCheckingAttempt::Final:
llvm_unreachable("should have exited already");
}
for (auto match : matches) {
auto matchDecl = match.Decl;
if (attempt == OverrideCheckingAttempt::PerfectMatch) {
diags.diagnose(matchDecl, diag::overridden_here);
continue;
}
auto diag = diags.diagnose(matchDecl, diag::overridden_near_match_here,
matchDecl->getDescriptiveKind(),
matchDecl->getFullName());
if (attempt == OverrideCheckingAttempt::BaseName) {
fixDeclarationName(diag, cast<AbstractFunctionDecl>(decl),
matchDecl->getFullName());
}
}
}
static bool parameterTypesMatch(const ValueDecl *derivedDecl,
const ValueDecl *baseDecl,
TypeMatchOptions matchMode) {
const ParameterList *derivedParams;
const ParameterList *baseParams;
if (auto *derived = dyn_cast<AbstractFunctionDecl>(derivedDecl)) {
auto *base = dyn_cast<AbstractFunctionDecl>(baseDecl);
if (!base)
return false;
baseParams = base->getParameterList(1);
derivedParams = derived->getParameterList(1);
} else {
auto *base = dyn_cast<SubscriptDecl>(baseDecl);
if (!base)
return false;
baseParams = base->getIndices();
derivedParams = cast<SubscriptDecl>(derivedDecl)->getIndices();
}
if (baseParams->size() != derivedParams->size())
return false;
auto subs = SubstitutionMap::getOverrideSubstitutions(baseDecl, derivedDecl,
/*derivedSubs=*/None);
for (auto i : indices(baseParams->getArray())) {
auto baseItfTy = baseParams->get(i)->getInterfaceType();
auto baseParamTy =
baseDecl->getAsGenericContext()->mapTypeIntoContext(baseItfTy);
baseParamTy = baseParamTy.subst(subs);
auto derivedParamTy = derivedParams->get(i)->getInterfaceType();
// Attempt contravariant match.
if (baseParamTy->matchesParameter(derivedParamTy, matchMode))
continue;
// Try once more for a match, using the underlying type of an
// IUO if we're allowing that.
if (baseParams->get(i)
->getAttrs()
.hasAttribute<ImplicitlyUnwrappedOptionalAttr>() &&
matchMode.contains(TypeMatchFlags::AllowNonOptionalForIUOParam)) {
baseParamTy = baseParamTy->getOptionalObjectType();
if (baseParamTy->matches(derivedParamTy, matchMode))
continue;
}
// If there is no match, then we're done.
return false;
}
return true;
}
namespace {
/// Class that handles the checking of a particular declaration against
/// superclass entities that it could override.
class OverrideMatcher {
TypeChecker &tc;
ASTContext &ctx;
ValueDecl *decl;
/// The superclass in which we'll look.
Type superclass;
// Cached member lookup results.
LookupResult members;
/// The lookup name used to find \c members.
DeclName membersName;
/// The type of the declaration, cached here once it has been computed.
Type cachedDeclType;
public:
OverrideMatcher(TypeChecker &tc, ValueDecl *decl);
/// Returns true when it's possible to perform any override matching.
explicit operator bool() const {
return static_cast<bool>(superclass);
}
/// Match this declaration against potential members in the superclass,
/// using the heuristics appropriate for the given \c attempt.
SmallVector<OverrideMatch, 2> match(OverrideCheckingAttempt attempt);
/// We have determined that we have an override of the given \c baseDecl.
///
/// Check that the override itself is valid.
bool checkOverride(ValueDecl *baseDecl,
OverrideCheckingAttempt attempt);
private:
/// Retrieve the type of the declaration, to be used in comparisons.
Type getDeclComparisonType() {
if (!cachedDeclType) {
cachedDeclType = getMemberTypeForComparison(ctx, decl);
}
return cachedDeclType;
}
};
}
OverrideMatcher::OverrideMatcher(TypeChecker &tc, ValueDecl *decl)
: tc(tc), ctx(decl->getASTContext()), decl(decl) {
// The final step for this constructor is to set up the superclass type,
// without which we will not perform an matching. Early exits therefore imply
// that there is no way we can match this declaration.
if (decl->isInvalid())
return;
auto *dc = decl->getDeclContext();
auto owningTy = dc->getDeclaredInterfaceType();
if (!owningTy)
return;
auto classDecl = owningTy->getClassOrBoundGenericClass();
if (!classDecl)
return;
// FIXME: Get the superclass from owningTy directly?
superclass = classDecl->getSuperclass();
}
SmallVector<OverrideMatch, 2> OverrideMatcher::match(
OverrideCheckingAttempt attempt) {
// If there's no matching we can do, fail.
if (!*this) return { };
auto dc = decl->getDeclContext();
// Determine what name we should look for.
DeclName name;
switch (attempt) {
case OverrideCheckingAttempt::PerfectMatch:
case OverrideCheckingAttempt::MismatchedOptional:
case OverrideCheckingAttempt::MismatchedTypes:
name = decl->getFullName();
break;
case OverrideCheckingAttempt::BaseName:
case OverrideCheckingAttempt::BaseNameWithMismatchedOptional:
name = decl->getBaseName();
break;
case OverrideCheckingAttempt::Final:
// Give up.
return { };
}
// If we don't have members available yet, or we looked them up based on a
// different name, look them up now.
if (members.empty() || name != membersName) {
auto lookupOptions = defaultMemberLookupOptions;
// Class methods cannot override declarations only
// visible via dynamic dispatch.
lookupOptions -= NameLookupFlags::DynamicLookup;
// Class methods cannot override declarations only
// visible as protocol requirements or protocol
// extension members.
lookupOptions -= NameLookupFlags::ProtocolMembers;
lookupOptions -= NameLookupFlags::PerformConformanceCheck;
membersName = name;
members = tc.lookupMember(dc, superclass, membersName, lookupOptions);
}
// Check each member we found.
SmallVector<OverrideMatch, 2> matches;
for (auto memberResult : members) {
auto parentDecl = memberResult.getValueDecl();
// Check whether there are any obvious reasons why the two given
// declarations do not have an overriding relationship.
if (!areOverrideCompatibleSimple(decl, parentDecl))
continue;
auto parentMethod = dyn_cast<AbstractFunctionDecl>(parentDecl);
auto parentStorage = dyn_cast<AbstractStorageDecl>(parentDecl);
assert(parentMethod || parentStorage);
(void)parentMethod;
(void)parentStorage;
// Check whether the types are identical.
auto parentDeclTy = getMemberTypeForComparison(ctx, parentDecl, decl);
if (parentDeclTy->hasError())
continue;
Type declTy = getDeclComparisonType();
if (isOverrideBasedOnType(decl, declTy, parentDecl, parentDeclTy)) {
matches.push_back({parentDecl, true, parentDeclTy});
continue;
}
// If this is a property, we accept the match and then reject it below
// if the types don't line up, since you can't overload properties based
// on types.
if (isa<VarDecl>(parentDecl) ||
attempt == OverrideCheckingAttempt::MismatchedTypes) {
matches.push_back({parentDecl, false, parentDeclTy});
continue;
}
// Failing that, check for subtyping.
TypeMatchOptions matchMode = TypeMatchFlags::AllowOverride;
if (attempt == OverrideCheckingAttempt::MismatchedOptional ||
attempt == OverrideCheckingAttempt::BaseNameWithMismatchedOptional){
matchMode |= TypeMatchFlags::AllowTopLevelOptionalMismatch;
} else if (parentDecl->isObjC()) {
matchMode |= TypeMatchFlags::AllowNonOptionalForIUOParam;
matchMode |= TypeMatchFlags::IgnoreNonEscapingForOptionalFunctionParam;
}
auto declFnTy = getDeclComparisonType()->getAs<AnyFunctionType>();
auto parentDeclFnTy = parentDeclTy->getAs<AnyFunctionType>();
if (declFnTy && parentDeclFnTy) {
auto paramsAndResultMatch = [=]() -> bool {
return parameterTypesMatch(decl, parentDecl, matchMode) &&
declFnTy->getResult()->matches(parentDeclFnTy->getResult(),
matchMode);
};
if (declFnTy->matchesFunctionType(parentDeclFnTy, matchMode,
paramsAndResultMatch)) {
matches.push_back({parentDecl, false, parentDeclTy});
continue;
}
} else if (getDeclComparisonType()->matches(parentDeclTy, matchMode)) {
matches.push_back({parentDecl, false, parentDeclTy});
continue;
}
}
// If we have more than one match, and any of them was exact, remove all
// non-exact matches.
if (matches.size() > 1) {
bool hadExactMatch = std::find_if(matches.begin(), matches.end(),
[](const OverrideMatch &match) {
return match.IsExact;
}) != matches.end();
if (hadExactMatch) {
matches.erase(std::remove_if(matches.begin(), matches.end(),
[&](const OverrideMatch &match) {
return !match.IsExact;
}),
matches.end());
}
}
return matches;
}
bool OverrideMatcher::checkOverride(ValueDecl *baseDecl,
OverrideCheckingAttempt attempt) {
auto &diags = ctx.Diags;
auto baseTy = getMemberTypeForComparison(ctx, baseDecl, decl);
bool emittedMatchError = false;
// If the name of our match differs from the name we were looking for,
// complain.
if (decl->getFullName() != baseDecl->getFullName()) {
auto diag = diags.diagnose(decl, diag::override_argument_name_mismatch,
isa<ConstructorDecl>(decl),
decl->getFullName(),
baseDecl->getFullName());
fixDeclarationName(diag, cast<AbstractFunctionDecl>(decl),
baseDecl->getFullName());
emittedMatchError = true;
}
// If we have an explicit ownership modifier and our parent doesn't,
// complain.
auto parentAttr =
baseDecl->getAttrs().getAttribute<ReferenceOwnershipAttr>();
if (auto ownershipAttr =
decl->getAttrs().getAttribute<ReferenceOwnershipAttr>()) {
ReferenceOwnership parentOwnership;
if (parentAttr)
parentOwnership = parentAttr->get();
else
parentOwnership = ReferenceOwnership::Strong;
if (parentOwnership != ownershipAttr->get()) {
diags.diagnose(decl, diag::override_ownership_mismatch,
parentOwnership, ownershipAttr->get());
diags.diagnose(baseDecl, diag::overridden_here);
}
}
// If a super method returns Self, and the subclass overrides it to
// instead return the subclass type, complain.
// This case gets this far because the type matching above specifically
// strips out dynamic self via replaceCovariantResultType(), and that
// is helpful in several cases - just not this one.
auto dc = decl->getDeclContext();
auto classDecl = dc->getAsClassOrClassExtensionContext();
if (decl->getASTContext().isSwiftVersionAtLeast(5) &&
baseDecl->getInterfaceType()->hasDynamicSelfType() &&
!decl->getInterfaceType()->hasDynamicSelfType() &&
!classDecl->isFinal()) {
diags.diagnose(decl, diag::override_dynamic_self_mismatch);
diags.diagnose(baseDecl, diag::overridden_here);
}
// Check that the override has the required access level.
// Overrides have to be at least as accessible as what they
// override, except:
// - they don't have to be more accessible than their class and
// - a final method may be public instead of open.
// Also diagnose attempts to override a non-open method from outside its
// defining module. This is not required for constructors, which are
// never really "overridden" in the intended sense here, because of
// course derived classes will change how the class is initialized.
AccessLevel matchAccess = baseDecl->getFormalAccess(dc);
if (matchAccess < AccessLevel::Open &&
baseDecl->getModuleContext() != decl->getModuleContext() &&
!isa<ConstructorDecl>(decl)) {
diags.diagnose(decl, diag::override_of_non_open,
decl->getDescriptiveKind());
} else if (matchAccess == AccessLevel::Open &&
classDecl->getFormalAccess(dc) ==
AccessLevel::Open &&
decl->getFormalAccess() != AccessLevel::Open &&
!decl->isFinal()) {
{
auto diag = diags.diagnose(decl, diag::override_not_accessible,
/*setter*/false,
decl->getDescriptiveKind(),
/*fromOverridden*/true);
fixItAccess(diag, decl, AccessLevel::Open);
}
diags.diagnose(baseDecl, diag::overridden_here);
} else if (!isa<ConstructorDecl>(decl)) {
auto matchAccessScope =
baseDecl->getFormalAccessScope(dc);
auto classAccessScope =
classDecl->getFormalAccessScope(dc);
auto requiredAccessScope =
matchAccessScope.intersectWith(classAccessScope);
auto scopeDC = requiredAccessScope->getDeclContext();
bool shouldDiagnose = !decl->isAccessibleFrom(scopeDC);
bool shouldDiagnoseSetter = false;
if (!shouldDiagnose && baseDecl->isSettable(dc)){
auto matchASD = cast<AbstractStorageDecl>(baseDecl);
if (matchASD->isSetterAccessibleFrom(dc)) {
auto matchSetterAccessScope = matchASD->getSetter()
->getFormalAccessScope(dc);
auto requiredSetterAccessScope =
matchSetterAccessScope.intersectWith(classAccessScope);
auto setterScopeDC = requiredSetterAccessScope->getDeclContext();
const auto *ASD = cast<AbstractStorageDecl>(decl);
shouldDiagnoseSetter =
ASD->isSettable(setterScopeDC) &&
!ASD->isSetterAccessibleFrom(setterScopeDC);
}
}
if (shouldDiagnose || shouldDiagnoseSetter) {
bool overriddenForcesAccess =
(requiredAccessScope->hasEqualDeclContextWith(matchAccessScope) &&
matchAccess != AccessLevel::Open);
AccessLevel requiredAccess =
requiredAccessScope->requiredAccessForDiagnostics();
{
auto diag = diags.diagnose(decl, diag::override_not_accessible,
shouldDiagnoseSetter,
decl->getDescriptiveKind(),
overriddenForcesAccess);
fixItAccess(diag, decl, requiredAccess, shouldDiagnoseSetter);
}
diags.diagnose(baseDecl, diag::overridden_here);
}
}
bool mayHaveMismatchedOptionals =
(attempt == OverrideCheckingAttempt::MismatchedOptional ||
attempt == OverrideCheckingAttempt::BaseNameWithMismatchedOptional);
auto declIUOAttr =
decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
auto matchDeclIUOAttr =
baseDecl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
// If this is an exact type match, we're successful!
Type declTy = getDeclComparisonType();
Type owningTy = dc->getDeclaredInterfaceType();
if (declIUOAttr == matchDeclIUOAttr && declTy->isEqual(baseTy)) {
// Nothing to do.
} else if (auto method = dyn_cast<AbstractFunctionDecl>(decl)) {
if (attempt == OverrideCheckingAttempt::MismatchedTypes) {
auto diagKind = diag::method_does_not_override;
if (isa<ConstructorDecl>(method))
diagKind = diag::initializer_does_not_override;
diags.diagnose(decl, diagKind);
noteFixableMismatchedTypes(decl, baseDecl);
diags.diagnose(baseDecl, diag::overridden_near_match_here,
baseDecl->getDescriptiveKind(),
baseDecl->getFullName());
emittedMatchError = true;
} else if (!isa<AccessorDecl>(method) &&
(baseDecl->isObjC() || mayHaveMismatchedOptionals)) {
// Private migration help for overrides of Objective-C methods.
TypeLoc resultTL;
if (auto *methodAsFunc = dyn_cast<FuncDecl>(method))
resultTL = methodAsFunc->getBodyResultTypeLoc();
emittedMatchError |= diagnoseMismatchedOptionals(
method, method->getParameterList(1), resultTL, baseDecl,
cast<AbstractFunctionDecl>(baseDecl)->getParameterList(1),
owningTy, mayHaveMismatchedOptionals);
}
} else if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
// Otherwise, if this is a subscript, validate that covariance is ok.
// If the parent is non-mutable, it's okay to be covariant.
auto parentSubscript = cast<SubscriptDecl>(baseDecl);
if (parentSubscript->getSetter()) {
diags.diagnose(subscript, diag::override_mutable_covariant_subscript,
declTy, baseTy);
diags.diagnose(baseDecl, diag::subscript_override_here);
return true;
}
if (attempt == OverrideCheckingAttempt::MismatchedTypes) {
diags.diagnose(decl, diag::subscript_does_not_override);
noteFixableMismatchedTypes(decl, baseDecl);
diags.diagnose(baseDecl, diag::overridden_near_match_here,
baseDecl->getDescriptiveKind(),
baseDecl->getFullName());
emittedMatchError = true;
} else if (mayHaveMismatchedOptionals) {
emittedMatchError |= diagnoseMismatchedOptionals(
subscript, subscript->getIndices(),
subscript->getElementTypeLoc(), baseDecl,
cast<SubscriptDecl>(baseDecl)->getIndices(), owningTy,
mayHaveMismatchedOptionals);
}
} else if (auto property = dyn_cast<VarDecl>(decl)) {
auto propertyTy = property->getInterfaceType();
auto parentPropertyTy = superclass->adjustSuperclassMemberDeclType(
baseDecl, decl, baseDecl->getInterfaceType());
if (!propertyTy->matches(parentPropertyTy,
TypeMatchFlags::AllowOverride)) {
diags.diagnose(property, diag::override_property_type_mismatch,
property->getName(), propertyTy, parentPropertyTy);
noteFixableMismatchedTypes(decl, baseDecl);
diags.diagnose(baseDecl, diag::property_override_here);
return true;
}
// Differing only in Optional vs. ImplicitlyUnwrappedOptional is fine.
bool IsSilentDifference = false;
if (auto propertyTyNoOptional = propertyTy->getOptionalObjectType())
if (auto parentPropertyTyNoOptional =
parentPropertyTy->getOptionalObjectType())
if (propertyTyNoOptional->isEqual(parentPropertyTyNoOptional))
IsSilentDifference = true;
// The overridden property must not be mutable.
if (cast<AbstractStorageDecl>(baseDecl)->getSetter() &&
!IsSilentDifference) {
diags.diagnose(property, diag::override_mutable_covariant_property,
property->getName(), parentPropertyTy, propertyTy);
diags.diagnose(baseDecl, diag::property_override_here);
return true;
}
}
// Catch-all to make sure we don't silently accept something we shouldn't.
if (attempt != OverrideCheckingAttempt::PerfectMatch &&
!emittedMatchError) {
OverrideMatch match{decl, /*isExact=*/false, declTy};
diagnoseGeneralOverrideFailure(decl, match, attempt);
}
return recordOverride(tc, decl, baseDecl);
}
/// Determine which method or subscript this method or subscript overrides
/// (if any).
///
/// \returns true if an error occurred.
bool swift::checkOverrides(TypeChecker &TC, ValueDecl *decl) {
// If we already computed overridden declarations and either succeeded
// or invalidated the attribute, there's nothing more to do.
if (decl->overriddenDeclsComputed()) {
// If we computed an overridden declaration successfully, we're done.
if (decl->getOverriddenDecl())
return false;
// If we set the override attribute to "invalid", we already diagnosed
// something here.
if (decl->getAttrs().hasAttribute<OverrideAttr>(/*AllowInvalid=*/true) &&
!decl->getAttrs().hasAttribute<OverrideAttr>())
return true;
// Otherwise, we have more checking to do.
}
// Set up matching, but bail out if there's nothing to match.
OverrideMatcher matcher(TC, decl);
if (!matcher) return false;
// Ignore accessor methods (e.g. getters and setters), they will be handled
// when their storage decl is processed.
// FIXME: We should pull information from the storage declaration, but
// that will be handled at a different point.
if (isa<AccessorDecl>(decl))
return false;
// Look for members with the same name and matching types as this
// one.
SmallVector<OverrideMatch, 2> matches;
auto attempt = OverrideCheckingAttempt::PerfectMatch;
do {
// Determine whether we should attempt to perform matching now, or exit
// early with a failure.
switch (attempt) {
case OverrideCheckingAttempt::PerfectMatch:
break;
case OverrideCheckingAttempt::MismatchedOptional:
// Don't keep looking if the user didn't indicate it's an override.
if (!decl->getAttrs().hasAttribute<OverrideAttr>())
return false;
break;
case OverrideCheckingAttempt::MismatchedTypes:
break;
case OverrideCheckingAttempt::BaseName:
// Don't keep looking if this is already a simple name, or if there
// are no arguments.
if (decl->getFullName() == decl->getBaseName() ||
decl->getFullName().getArgumentNames().empty())
return false;
break;
case OverrideCheckingAttempt::BaseNameWithMismatchedOptional:
break;
case OverrideCheckingAttempt::Final:
// Give up.
return false;
}
// Try to match with the
matches = matcher.match(attempt);
if (!matches.empty())
break;
// Try the next version.
++attempt;
} while (true);
assert(!matches.empty());
// If we override more than one declaration, complain.
if (matches.size() > 1) {
diagnoseGeneralOverrideFailure(decl, matches, attempt);
return true;
}
// If we have a single match (exact or not), take it.
return matcher.checkOverride(matches.front().Decl, attempt);
}
namespace {
/// Attribute visitor that checks how the given attribute should be
/// considered when overriding a declaration.
///
/// Note that the attributes visited are those of the base
/// declaration, so if you need to check that the overriding
/// declaration doesn't have an attribute if the base doesn't have
/// it, this isn't sufficient.
class AttributeOverrideChecker
: public AttributeVisitor<AttributeOverrideChecker> {
ValueDecl *Base;
ValueDecl *Override;
DiagnosticEngine &Diags;
public:
AttributeOverrideChecker(ValueDecl *base, ValueDecl *override)
: Base(base), Override(override), Diags(base->getASTContext().Diags) { }
/// Deleting this ensures that all attributes are covered by the visitor
/// below.
void visitDeclAttribute(DeclAttribute *A) = delete;
#define UNINTERESTING_ATTR(CLASS) \
void visit##CLASS##Attr(CLASS##Attr *) {}
UNINTERESTING_ATTR(AccessControl)
UNINTERESTING_ATTR(Alignment)
UNINTERESTING_ATTR(CDecl)
UNINTERESTING_ATTR(Consuming)
UNINTERESTING_ATTR(DynamicMemberLookup)
UNINTERESTING_ATTR(SILGenName)
UNINTERESTING_ATTR(Exported)
UNINTERESTING_ATTR(ForbidSerializingReference)
UNINTERESTING_ATTR(GKInspectable)
UNINTERESTING_ATTR(IBAction)
UNINTERESTING_ATTR(IBDesignable)
UNINTERESTING_ATTR(IBInspectable)
UNINTERESTING_ATTR(IBOutlet)
UNINTERESTING_ATTR(Indirect)
UNINTERESTING_ATTR(Inline)
UNINTERESTING_ATTR(Optimize)
UNINTERESTING_ATTR(Inlinable)
UNINTERESTING_ATTR(Effects)
UNINTERESTING_ATTR(FixedLayout)
UNINTERESTING_ATTR(Lazy)
UNINTERESTING_ATTR(LLDBDebuggerFunction)
UNINTERESTING_ATTR(Mutating)
UNINTERESTING_ATTR(NonMutating)
UNINTERESTING_ATTR(NonObjC)
UNINTERESTING_ATTR(NoReturn)
UNINTERESTING_ATTR(NSApplicationMain)
UNINTERESTING_ATTR(NSCopying)
UNINTERESTING_ATTR(NSManaged)
UNINTERESTING_ATTR(ObjCBridged)
UNINTERESTING_ATTR(Optional)
UNINTERESTING_ATTR(Override)
UNINTERESTING_ATTR(RawDocComment)
UNINTERESTING_ATTR(Required)
UNINTERESTING_ATTR(Convenience)
UNINTERESTING_ATTR(Semantics)
UNINTERESTING_ATTR(SetterAccess)
UNINTERESTING_ATTR(UIApplicationMain)
UNINTERESTING_ATTR(UsableFromInline)
UNINTERESTING_ATTR(ObjCNonLazyRealization)
UNINTERESTING_ATTR(UnsafeNoObjCTaggedPointer)
UNINTERESTING_ATTR(SwiftNativeObjCRuntimeBase)
UNINTERESTING_ATTR(ShowInInterface)
UNINTERESTING_ATTR(Specialize)
// These can't appear on overridable declarations.
UNINTERESTING_ATTR(Prefix)
UNINTERESTING_ATTR(Postfix)
UNINTERESTING_ATTR(Infix)
UNINTERESTING_ATTR(ReferenceOwnership)
UNINTERESTING_ATTR(SynthesizedProtocol)
UNINTERESTING_ATTR(RequiresStoredPropertyInits)
UNINTERESTING_ATTR(Transparent)
UNINTERESTING_ATTR(SILStored)
UNINTERESTING_ATTR(Testable)
UNINTERESTING_ATTR(WarnUnqualifiedAccess)
UNINTERESTING_ATTR(DiscardableResult)
UNINTERESTING_ATTR(ObjCMembers)
UNINTERESTING_ATTR(ObjCRuntimeName)
UNINTERESTING_ATTR(RestatedObjCConformance)
UNINTERESTING_ATTR(Implements)
UNINTERESTING_ATTR(StaticInitializeObjCMetadata)
UNINTERESTING_ATTR(DowngradeExhaustivityCheck)
UNINTERESTING_ATTR(ImplicitlyUnwrappedOptional)
UNINTERESTING_ATTR(ClangImporterSynthesizedType)
UNINTERESTING_ATTR(WeakLinked)
UNINTERESTING_ATTR(Frozen)
#undef UNINTERESTING_ATTR
void visitAvailableAttr(AvailableAttr *attr) {
// FIXME: Check that this declaration is at least as available as the
// one it overrides.
}
void visitRethrowsAttr(RethrowsAttr *attr) {
// 'rethrows' functions are a subtype of ordinary 'throws' functions.
// Require 'rethrows' on the override if it was there on the base,
// unless the override is completely non-throwing.
if (!Override->getAttrs().hasAttribute<RethrowsAttr>() &&
cast<AbstractFunctionDecl>(Override)->hasThrows()) {
Diags.diagnose(Override, diag::override_rethrows_with_non_rethrows,
isa<ConstructorDecl>(Override));
Diags.diagnose(Base, diag::overridden_here);
}
}
void visitFinalAttr(FinalAttr *attr) {
// If this is an accessor, don't complain if we would have
// complained about the storage declaration.
if (auto accessor = dyn_cast<AccessorDecl>(Override)) {
if (auto storageDecl = accessor->getStorage()) {
if (storageDecl->getOverriddenDecl() &&
storageDecl->getOverriddenDecl()->isFinal())
return;
}
}
// FIXME: Customize message to the kind of thing.
auto baseKind = Base->getDescriptiveKind();
switch (baseKind) {
case DescriptiveDeclKind::StaticLet:
case DescriptiveDeclKind::StaticVar:
case DescriptiveDeclKind::StaticMethod:
Diags.diagnose(Override, diag::override_static, baseKind);
break;
default:
Diags.diagnose(Override, diag::override_final,
Override->getDescriptiveKind(), baseKind);
break;
}
Diags.diagnose(Base, diag::overridden_here);
}
void visitDynamicAttr(DynamicAttr *attr) {
// Final overrides are not dynamic.
if (Override->isFinal())
return;
// Must be @objc to be 'dynamic'.
if (!Override->isObjC())
return;
makeDynamic(Override->getASTContext(), Override);
}
void visitObjCAttr(ObjCAttr *attr) {
// Checking for overrides of declarations that are implicitly @objc
// and occur in class extensions, because overriding will no longer be
// possible under the Swift 4 rules.
// We only care about the storage declaration.
if (isa<AccessorDecl>(Override)) return;
// If @objc was explicit or handled elsewhere, nothing to do.
if (!attr->isSwift3Inferred()) return;
// If we aren't warning about Swift 3 @objc inference, we're done.
if (Override->getASTContext().LangOpts.WarnSwift3ObjCInference ==
Swift3ObjCInferenceWarnings::None)
return;
// If 'dynamic' was implicit, we'll already have warned about this.
if (auto dynamicAttr = Base->getAttrs().getAttribute<DynamicAttr>()) {
if (!dynamicAttr->isImplicit()) return;
}
// The overridden declaration needs to be in an extension.
if (!isa<ExtensionDecl>(Base->getDeclContext())) return;
// Complain.
Diags.diagnose(Override, diag::override_swift3_objc_inference,
Override->getDescriptiveKind(),
Override->getFullName(),
Base->getDeclContext()
->getAsNominalTypeOrNominalTypeExtensionContext()
->getName());
Diags.diagnose(Base, diag::make_decl_objc, Base->getDescriptiveKind())
.fixItInsert(Base->getAttributeInsertionLoc(false),
"@objc ");
}
};
} // end anonymous namespace
/// Determine whether overriding the given declaration requires a keyword.
bool swift::overrideRequiresKeyword(ValueDecl *overridden) {
if (auto ctor = dyn_cast<ConstructorDecl>(overridden)) {
return ctor->isDesignatedInit() && !ctor->isRequired();
}
return true;
}
/// \brief Returns true if the availability of the overriding declaration
/// makes it a safe override, given the availability of the base declaration.
static bool isAvailabilitySafeForOverride(ValueDecl *override,
ValueDecl *base) {
ASTContext &ctx = override->getASTContext();
// API availability ranges are contravariant: make sure the version range
// of an overridden declaration is fully contained in the range of the
// overriding declaration.
AvailabilityContext overrideInfo =
AvailabilityInference::availableRange(override, ctx);
AvailabilityContext baseInfo =
AvailabilityInference::availableRange(base, ctx);
return baseInfo.isContainedIn(overrideInfo);
}
/// Returns true if a diagnostic about an accessor being less available
/// than the accessor it overrides would be redundant because we will
/// already emit another diagnostic.
static bool
isRedundantAccessorOverrideAvailabilityDiagnostic(ValueDecl *override,
ValueDecl *base) {
auto *overrideFn = dyn_cast<AccessorDecl>(override);
auto *baseFn = dyn_cast<AccessorDecl>(base);
if (!overrideFn || !baseFn)
return false;
AbstractStorageDecl *overrideASD = overrideFn->getStorage();
AbstractStorageDecl *baseASD = baseFn->getStorage();
if (overrideASD->getOverriddenDecl() != baseASD)
return false;
// If we have already emitted a diagnostic about an unsafe override
// for the property, don't complain about the accessor.
if (!isAvailabilitySafeForOverride(overrideASD, baseASD)) {
return true;
}
// Returns true if we will already diagnose a bad override
// on the property's accessor of the given kind.
auto accessorOverrideAlreadyDiagnosed = [&](AccessorKind kind) {
FuncDecl *overrideAccessor = overrideASD->getAccessor(kind);
FuncDecl *baseAccessor = baseASD->getAccessor(kind);
if (overrideAccessor && baseAccessor &&
!isAvailabilitySafeForOverride(overrideAccessor, baseAccessor)) {
return true;
}
return false;
};
// If we have already emitted a diagnostic about an unsafe override
// for a getter or a setter, no need to complain about materializeForSet,
// which is synthesized to be as available as both the getter and
// the setter.
if (overrideFn->isMaterializeForSet()) {
if (accessorOverrideAlreadyDiagnosed(AccessorKind::Get) ||
accessorOverrideAlreadyDiagnosed(AccessorKind::Set)) {
return true;
}
}
return false;
}
/// Diagnose an override for potential availability. Returns true if
/// a diagnostic was emitted and false otherwise.
static bool diagnoseOverrideForAvailability(ValueDecl *override,
ValueDecl *base) {
if (isAvailabilitySafeForOverride(override, base))
return false;
// Suppress diagnostics about availability overrides for accessors
// if they would be redundant with other diagnostics.
if (isRedundantAccessorOverrideAvailabilityDiagnostic(override, base))
return false;
auto &diags = override->getASTContext().Diags;
if (auto *accessor = dyn_cast<AccessorDecl>(override)) {
diags.diagnose(override, diag::override_accessor_less_available,
accessor->getDescriptiveKind(),
accessor->getStorage()->getBaseName());
diags.diagnose(base, diag::overridden_here);
return true;
}
diags.diagnose(override, diag::override_less_available,
override->getBaseName());
diags.diagnose(base, diag::overridden_here);
return true;
}
static bool recordOverride(TypeChecker &TC, ValueDecl *override,
ValueDecl *base, bool isKnownObjC) {
// This can happen with circular inheritance.
if (override == base)
return true;
ASTContext &ctx = override->getASTContext();
auto &diags = ctx.Diags;
// Check property and subscript overriding.
if (auto *baseASD = dyn_cast<AbstractStorageDecl>(base)) {
auto *overrideASD = cast<AbstractStorageDecl>(override);
// Make sure that the overriding property doesn't have storage.
if (overrideASD->hasStorage() &&
!(overrideASD->getWillSetFunc() || overrideASD->getDidSetFunc())) {
bool downgradeToWarning = false;
if (!ctx.isSwiftVersionAtLeast(5) &&
overrideASD->getAttrs().hasAttribute<LazyAttr>()) {
// Swift 4.0 had a bug where lazy properties were considered
// computed by the time of this check. Downgrade this diagnostic to
// a warning.
downgradeToWarning = true;
}
auto diagID = downgradeToWarning ?
diag::override_with_stored_property_warn :
diag::override_with_stored_property;
diags.diagnose(overrideASD, diagID,
overrideASD->getBaseName().getIdentifier());
diags.diagnose(baseASD, diag::property_override_here);
if (!downgradeToWarning)
return true;
}
// Make sure that an observing property isn't observing something
// read-only. Observing properties look at change, read-only properties
// have nothing to observe!
bool baseIsSettable = baseASD->isSettable(baseASD->getDeclContext());
if (baseIsSettable && ctx.LangOpts.EnableAccessControl) {
baseIsSettable =
baseASD->isSetterAccessibleFrom(overrideASD->getDeclContext());
}
if (overrideASD->getWriteImpl() == WriteImplKind::InheritedWithObservers
&& !baseIsSettable) {
diags.diagnose(overrideASD, diag::observing_readonly_property,
overrideASD->getBaseName().getIdentifier());
diags.diagnose(baseASD, diag::property_override_here);
return true;
}
// Make sure we're not overriding a settable property with a non-settable
// one. The only reasonable semantics for this would be to inherit the
// setter but override the getter, and that would be surprising at best.
if (baseIsSettable && !override->isSettable(override->getDeclContext())) {
diags.diagnose(overrideASD, diag::override_mutable_with_readonly_property,
overrideASD->getBaseName().getIdentifier());
diags.diagnose(baseASD, diag::property_override_here);
return true;
}
// Make sure a 'let' property is only overridden by 'let' properties. A
// let property provides more guarantees than the getter of a 'var'
// property.
if (auto VD = dyn_cast<VarDecl>(baseASD)) {
if (VD->isLet()) {
diags.diagnose(overrideASD, diag::override_let_property,
VD->getName());
diags.diagnose(baseASD, diag::property_override_here);
return true;
}
}
}
// Non-Objective-C declarations in extensions cannot override or
// be overridden.
if ((base->getDeclContext()->isExtensionContext() ||
override->getDeclContext()->isExtensionContext()) &&
!base->isObjC() && !isKnownObjC) {
bool baseCanBeObjC = canBeRepresentedInObjC(base);
diags.diagnose(override, diag::override_decl_extension, baseCanBeObjC,
!base->getDeclContext()->isExtensionContext());
if (baseCanBeObjC) {
SourceLoc insertionLoc =
override->getAttributeInsertionLoc(/*forModifier=*/false);
diags.diagnose(base, diag::overridden_here_can_be_objc)
.fixItInsert(insertionLoc, "@objc ");
} else {
diags.diagnose(base, diag::overridden_here);
}
return true;
}
// If the overriding declaration does not have the 'override' modifier on
// it, complain.
if (!override->getAttrs().hasAttribute<OverrideAttr>() &&
overrideRequiresKeyword(base)) {
// FIXME: rdar://16320042 - For properties, we don't have a useful
// location for the 'var' token. Instead of emitting a bogus fixit, only
// emit the fixit for 'func's.
if (!isa<VarDecl>(override))
diags.diagnose(override, diag::missing_override)
.fixItInsert(override->getStartLoc(), "override ");
else
diags.diagnose(override, diag::missing_override);
diags.diagnose(base, diag::overridden_here);
override->getAttrs().add(new (ctx) OverrideAttr(SourceLoc()));
}
// If the overridden method is declared in a Swift Class Declaration,
// dispatch will use table dispatch. If the override is in an extension
// warn, since it is not added to the class vtable.
//
// FIXME: Only warn if the extension is in another module, and if
// it is in the same module, update the vtable.
if (auto *baseDecl = dyn_cast<ClassDecl>(base->getDeclContext())) {
if (baseDecl->hasKnownSwiftImplementation() &&
!base->isDynamic() && !isKnownObjC &&
override->getDeclContext()->isExtensionContext()) {
// For compatibility, only generate a warning in Swift 3
diags.diagnose(override, (ctx.isSwiftVersion3()
? diag::override_class_declaration_in_extension_warning
: diag::override_class_declaration_in_extension));
diags.diagnose(base, diag::overridden_here);
}
}
// If the overriding declaration is 'throws' but the base is not,
// complain.
if (auto overrideFn = dyn_cast<AbstractFunctionDecl>(override)) {
if (overrideFn->hasThrows() &&
!cast<AbstractFunctionDecl>(base)->hasThrows()) {
diags.diagnose(override, diag::override_throws,
isa<ConstructorDecl>(override));
diags.diagnose(base, diag::overridden_here);
}
if (!overrideFn->hasThrows() && base->isObjC() &&
cast<AbstractFunctionDecl>(base)->hasThrows()) {
diags.diagnose(override, diag::override_throws_objc,
isa<ConstructorDecl>(override));
diags.diagnose(base, diag::overridden_here);
}
}
// FIXME: Possibly should extend to more availability checking.
if (auto *attr = base->getAttrs().getUnavailable(ctx)) {
diagnoseUnavailableOverride(override, base, attr);
}
if (!ctx.LangOpts.DisableAvailabilityChecking) {
diagnoseOverrideForAvailability(override, base);
}
if (auto overridingFunc = dyn_cast<FuncDecl>(override)) {
overridingFunc->setOverriddenDecl(cast<FuncDecl>(base));
} else if (auto overridingCtor = dyn_cast<ConstructorDecl>(override)) {
overridingCtor->setOverriddenDecl(cast<ConstructorDecl>(base));
} else if (auto overridingASD = dyn_cast<AbstractStorageDecl>(override)) {
auto *baseASD = cast<AbstractStorageDecl>(base);
overridingASD->setOverriddenDecl(baseASD);
} else {
llvm_unreachable("Unexpected decl");
}
/// Check attributes associated with the base; some may need to merged with
/// or checked against attributes in the overriding declaration.
AttributeOverrideChecker attrChecker(base, override);
for (auto attr : base->getAttrs()) {
attrChecker.visit(attr);
}
if (auto overridingASD = dyn_cast<AbstractStorageDecl>(override)) {
// Make sure we get consistent overrides for the accessors as well.
auto *baseASD = cast<AbstractStorageDecl>(base);
assert(baseASD->getGetter());
auto recordAccessorOverride = [&](AccessorKind kind) {
// We need the same accessor on both.
auto baseAccessor = baseASD->getAccessor(kind);
if (!baseAccessor) return;
auto overridingAccessor = overridingASD->getAccessor(kind);
if (!overridingAccessor) return;
// For setter accessors, we need the base's setter to be
// accessible from the overriding context, or it's not an override.
if ((kind == AccessorKind::Set ||
kind == AccessorKind::MaterializeForSet) &&
!baseASD->isSetterAccessibleFrom(overridingASD->getDeclContext()))
return;
// A materializeForSet for an override of storage with a
// forced static dispatch materializeForSet is not itself an
// override.
if (kind == AccessorKind::MaterializeForSet &&
baseAccessor->hasForcedStaticDispatch())
return;
// FIXME: Egregious hack to set an 'override' attribute.
if (!overridingAccessor->getAttrs().hasAttribute<OverrideAttr>()) {
auto loc = overridingASD->getOverrideLoc();
overridingAccessor->getAttrs().add(
new (ctx) OverrideAttr(loc));
}
recordOverride(TC, overridingAccessor, baseAccessor, baseASD->isObjC());
};
// FIXME: Another list of accessors, yay!
recordAccessorOverride(AccessorKind::Get);
recordAccessorOverride(AccessorKind::Set);
recordAccessorOverride(AccessorKind::MaterializeForSet);
}
return false;
}
/// Minimize the set of overridden associated types, eliminating any
/// associated types that are overridden by other associated types.
static void minimizeOverriddenAssociatedTypes(
SmallVectorImpl<ValueDecl *> &assocTypes) {
// Mark associated types that are "worse" than some other associated type,
// because they come from an inherited protocol.
bool anyWorse = false;
std::vector<bool> worseThanAny(assocTypes.size(), false);
for (unsigned i : indices(assocTypes)) {
auto assoc1 = cast<AssociatedTypeDecl>(assocTypes[i]);
auto proto1 = assoc1->getProtocol();
for (unsigned j : range(i + 1, assocTypes.size())) {
auto assoc2 = cast<AssociatedTypeDecl>(assocTypes[j]);
auto proto2 = assoc2->getProtocol();
if (proto1->inheritsFrom(proto2)) {
anyWorse = true;
worseThanAny[j] = true;
} else if (proto2->inheritsFrom(proto1)) {
anyWorse = true;
worseThanAny[i] = true;
break;
}
}
}
// If we didn't find any associated types that were "worse", we're done.
if (!anyWorse) return;
// Copy in the associated types that aren't worse than any other associated
// type.
unsigned nextIndex = 0;
for (unsigned i : indices(assocTypes)) {
if (worseThanAny[i]) continue;
assocTypes[nextIndex++] = assocTypes[i];
}
assocTypes.erase(assocTypes.begin() + nextIndex, assocTypes.end());
}
/// Sort associated types just based on the protocol.
static int compareSimilarAssociatedTypes(ValueDecl *const *lhs,
ValueDecl *const *rhs) {
auto lhsProto = cast<AssociatedTypeDecl>(*lhs)->getProtocol();
auto rhsProto = cast<AssociatedTypeDecl>(*rhs)->getProtocol();
return TypeDecl::compare(lhsProto, rhsProto);
}
/// Compute the set of associated types that are overridden by the given
/// associated type.
static SmallVector<ValueDecl *, 4>
computeOverriddenAssociatedTypes(AssociatedTypeDecl *assocType) {
// Find associated types with the given name in all of the inherited
// protocols.
SmallVector<ValueDecl *, 4> overriddenAssocTypes;
auto proto = assocType->getProtocol();
proto->walkInheritedProtocols([&](ProtocolDecl *inheritedProto) {
if (proto == inheritedProto) return TypeWalker::Action::Continue;
// Objective-C protocols
if (inheritedProto->isObjC()) return TypeWalker::Action::Continue;
// Look for associated types with the same name.
bool foundAny = false;
for (auto member : inheritedProto->lookupDirect(
assocType->getFullName(),
/*ignoreNewExtensions=*/true)) {
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
overriddenAssocTypes.push_back(assocType);
foundAny = true;
}
}
return foundAny ? TypeWalker::Action::SkipChildren
: TypeWalker::Action::Continue;
});
// Minimize the set of inherited associated types, eliminating any that
// themselves are overridden.
minimizeOverriddenAssociatedTypes(overriddenAssocTypes);
// Sort the set of inherited associated types.
llvm::array_pod_sort(overriddenAssocTypes.begin(),
overriddenAssocTypes.end(),
compareSimilarAssociatedTypes);
return overriddenAssocTypes;
}
void TypeChecker::resolveOverriddenDecl(ValueDecl *VD) {
// If this function or something it calls didn't set any overridden
// declarations, it means that there are no overridden declarations. Set
// the empty list.
// Note: the request-evaluator would do this for free, but this function
// is still fundamentally stateful.
SWIFT_DEFER {
if (!VD->overriddenDeclsComputed())
(void)VD->setOverriddenDecls({ });
};
// For an associated type, compute the (minimized) set of overridden
// declarations.
if (auto assocType = dyn_cast<AssociatedTypeDecl>(VD)) {
// Assume there are no overridden declarations for the purposes of this
// computation.
// FIXME: The request-evaluator will eventually handle this for us.
(void)assocType->setOverriddenDecls({ });
auto overriddenAssocTypes = computeOverriddenAssociatedTypes(assocType);
(void)assocType->setOverriddenDecls(overriddenAssocTypes);
return;
}
// Only members of classes can override other declarations.
if (!VD->getDeclContext()->getAsClassOrClassExtensionContext())
return;
// Types that aren't associated types cannot be overridden.
if (isa<TypeDecl>(VD))
return;
// Only initializers and declarations marked with the 'override' declaration
// modifier can override declarations.
if (!isa<ConstructorDecl>(VD) && !VD->getAttrs().hasAttribute<OverrideAttr>())
return;
// Invalidate an existing "override" attribute or add a new invalid "override"
// attribute, which will suppress additional checking.
auto invalidateOverrideAttribute = [VD]() {
auto overrideAttr = VD->getAttrs().getAttribute<OverrideAttr>(true);
if (!overrideAttr) {
overrideAttr = new (VD->getASTContext()) OverrideAttr(true);
VD->getAttrs().add(overrideAttr);
}
overrideAttr->setInvalid();
};
// Try to match potential overridden declarations.
OverrideMatcher matcher(*this, VD);
if (!matcher) {
return;
}
auto matches = matcher.match(OverrideCheckingAttempt::PerfectMatch);
if (matches.empty()) {
return;
}
// If we have more than one potential match, diagnose the ambiguity and
// fail.
if (matches.size() > 1) {
diagnoseGeneralOverrideFailure(VD, matches,
OverrideCheckingAttempt::PerfectMatch);
invalidateOverrideAttribute();
return;
}
// Check the correctness of the override.
// FIXME: This also records the override.
if (matcher.checkOverride(matches.front().Decl,
OverrideCheckingAttempt::PerfectMatch))
invalidateOverrideAttribute();
}