blob: 495ef53ba8018b78c3fb9864aa9947fea7069cbc [file] [log] [blame]
//===--- ResilienceDiagnostics.cpp - Resilience Inlineability Diagnostics -===//
//
// 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 diagnostics for @inlineable.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "swift/AST/Attr.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/DeclContext.h"
using namespace swift;
enum FragileFunctionKind : unsigned {
Transparent,
InlineAlways,
Inlineable,
DefaultArgument
};
FragileFunctionKind getFragileFunctionKind(const DeclContext *DC) {
for (; DC->isLocalContext(); DC = DC->getParent()) {
if (auto *DAI = dyn_cast<DefaultArgumentInitializer>(DC))
if (DAI->getResilienceExpansion() == ResilienceExpansion::Minimal)
return FragileFunctionKind::DefaultArgument;
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC)) {
// If the function is a nested function, we will serialize its body if
// we serialize the parent's body.
if (AFD->getDeclContext()->isLocalContext())
continue;
// Bodies of public transparent and always-inline functions are
// serialized, so use conservative access patterns.
if (AFD->isTransparent())
return FragileFunctionKind::Transparent;
if (AFD->getAttrs().hasAttribute<InlineableAttr>())
return FragileFunctionKind::Inlineable;
if (auto attr = AFD->getAttrs().getAttribute<InlineAttr>())
if (attr->getKind() == InlineKind::Always)
return FragileFunctionKind::InlineAlways;
// If a property or subscript is @_inlineable, the accessors are
// @_inlineable also.
if (auto FD = dyn_cast<FuncDecl>(AFD))
if (auto *ASD = FD->getAccessorStorageDecl())
if (ASD->getAttrs().getAttribute<InlineableAttr>())
return FragileFunctionKind::Inlineable;
}
}
llvm_unreachable("Context is not nested inside a fragile function");
}
void TypeChecker::diagnoseInlineableLocalType(const NominalTypeDecl *NTD) {
auto *DC = NTD->getDeclContext();
auto expansion = DC->getResilienceExpansion();
if (expansion == ResilienceExpansion::Minimal) {
diagnose(NTD, diag::local_type_in_inlineable_function,
NTD->getFullName(), getFragileFunctionKind(DC));
}
}
bool TypeChecker::diagnoseInlineableDeclRef(SourceLoc loc,
const ValueDecl *D,
const DeclContext *DC) {
auto expansion = DC->getResilienceExpansion();
if (expansion == ResilienceExpansion::Minimal) {
if (!isa<GenericTypeParamDecl>(D) &&
// FIXME: Figure out what to do with typealiases
!isa<TypeAliasDecl>(D) &&
!D->getDeclContext()->isLocalContext() &&
D->hasAccessibility()) {
if (D->getEffectiveAccess() < Accessibility::Public) {
diagnose(loc, diag::resilience_decl_unavailable,
D->getDescriptiveKind(), D->getFullName(),
D->getFormalAccess(), getFragileFunctionKind(DC));
diagnose(D, diag::resilience_decl_declared_here,
D->getDescriptiveKind(), D->getFullName());
return true;
}
}
}
return false;
}