mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Compile Time Values] Add syntactic verification of valid expressions in '@const' contexts
Syntactically verify that initializer expressions of '@const' variables and argument expressions to '@const' parameters consist strictly of syntactically-verifiable set of basic values and operations
This commit is contained in:
@@ -816,9 +816,34 @@ ERROR(cannot_return_value_from_void_func,none,
|
||||
NOTE(add_return_type_note,none,
|
||||
"did you mean to add a return type?", ())
|
||||
|
||||
ERROR(expect_compile_time_const,none,
|
||||
ERROR(expect_compile_time_literal,none,
|
||||
"expect a compile-time constant literal", ())
|
||||
|
||||
ERROR(const_unsupported_enum_associated_value,none,
|
||||
"enums with associated values not supported in a '@const' expression", ())
|
||||
ERROR(const_unsupported_operator,none,
|
||||
"unsupported operator in a '@const' expression", ())
|
||||
ERROR(const_unsupported_type,none,
|
||||
"unsupported type in a '@const' expression", ())
|
||||
ERROR(const_unsupported_type_expr,none,
|
||||
"type expressions not supported in a '@const' expression", ())
|
||||
ERROR(const_unsupported_closure,none,
|
||||
"closures not supported in a '@const' expression", ())
|
||||
ERROR(const_unsupported_keypath,none,
|
||||
"keypaths not supported in a '@const' expression", ())
|
||||
ERROR(const_opaque_decl_ref,none,
|
||||
"unable to resolve variable reference in a '@const' expression", ())
|
||||
ERROR(const_opaque_func_decl_ref,none,
|
||||
"unable to resolve function reference in a '@const' expression", ())
|
||||
ERROR(const_non_convention_c_conversion,none,
|
||||
"only 'convention(c)' function values are supported in a '@const' expression", ())
|
||||
ERROR(const_opaque_callee,none,
|
||||
"unable to resolve callee in a '@const' expression", ())
|
||||
ERROR(const_non_const_param,none,
|
||||
"reference to a non-'@const' parameter in a '@const' expression", ())
|
||||
ERROR(const_unknown_default,none,
|
||||
"not supported in a '@const' expression", ())
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// MARK: Import Resolution
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -497,6 +497,9 @@ EXPERIMENTAL_FEATURE(InlineArrayTypeSugar, false)
|
||||
/// Allow declaration of compile-time values
|
||||
EXPERIMENTAL_FEATURE(CompileTimeValues, true)
|
||||
|
||||
/// Allow declaration of compile-time values
|
||||
EXPERIMENTAL_FEATURE(CompileTimeValuesPreview, false)
|
||||
|
||||
/// Allow function body macros applied to closures.
|
||||
EXPERIMENTAL_FEATURE(ClosureBodyMacro, true)
|
||||
|
||||
|
||||
@@ -408,6 +408,10 @@ static bool usesFeatureCompileTimeValues(Decl *decl) {
|
||||
decl->getAttrs().hasAttribute<ConstInitializedAttr>();
|
||||
}
|
||||
|
||||
static bool usesFeatureCompileTimeValuesPreview(Decl *decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool usesFeatureClosureBodyMacro(Decl *decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ add_swift_host_library(swiftSema STATIC
|
||||
DerivedConformance/DerivedConformanceRawRepresentable.cpp
|
||||
ImportResolution.cpp
|
||||
InstrumenterSupport.cpp
|
||||
LegalConstExprVerifier.cpp
|
||||
LookupVisibleDecls.cpp
|
||||
MiscDiagnostics.cpp
|
||||
OpenedExistentials.cpp
|
||||
|
||||
@@ -6521,7 +6521,7 @@ bool ExtraneousReturnFailure::diagnoseAsError() {
|
||||
}
|
||||
|
||||
bool NotCompileTimeLiteralFailure::diagnoseAsError() {
|
||||
emitDiagnostic(diag::expect_compile_time_const);
|
||||
emitDiagnostic(diag::expect_compile_time_literal);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
379
lib/Sema/LegalConstExprVerifier.cpp
Normal file
379
lib/Sema/LegalConstExprVerifier.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
//===--------------------- LegalConstExprVerifier.cpp ---------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2025 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 syntactic validation that a `@const` expression
|
||||
// consists strictly of values and operations on those values as allowed
|
||||
// by the `@const` feature specification at this time.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MiscDiagnostics.h"
|
||||
#include "TypeChecker.h"
|
||||
#include "swift/AST/ASTContext.h"
|
||||
#include "swift/AST/ASTWalker.h"
|
||||
#include "swift/AST/ParameterList.h"
|
||||
#include "swift/AST/SemanticAttrs.h"
|
||||
#include "swift/Basic/Assertions.h"
|
||||
using namespace swift;
|
||||
|
||||
namespace {
|
||||
static bool isIntegerType(Type type) {
|
||||
return type->isInt() || type->isInt8() || type->isInt16() ||
|
||||
type->isInt32() || type->isInt64() || type->isUInt() ||
|
||||
type->isUInt8() || type->isUInt16() || type->isUInt32() ||
|
||||
type->isUInt64();
|
||||
}
|
||||
|
||||
static bool isFloatType(Type type) {
|
||||
// TODO: CGFloat?
|
||||
return type->isFloat() || type->isDouble() || type->isFloat80();
|
||||
}
|
||||
|
||||
enum IllegalConstErrorDiagnosis {
|
||||
TypeNotSupported,
|
||||
AssociatedValue,
|
||||
UnsupportedBinaryOperator,
|
||||
UnsupportedUnaryOperator,
|
||||
TypeExpression,
|
||||
KeyPath,
|
||||
Closue,
|
||||
OpaqueDeclRef,
|
||||
OpaqueFuncDeclRef,
|
||||
NonConventionCFunc,
|
||||
OpaqueCalleeRef,
|
||||
NonConstParameter,
|
||||
Default
|
||||
};
|
||||
|
||||
/// Given a provided error expression \p errorExpr, and the reason
|
||||
/// \p reason for the failure, emit corresponding diagnostic.
|
||||
static void diagnoseError(const Expr *errorExpr,
|
||||
IllegalConstErrorDiagnosis reason,
|
||||
DiagnosticEngine &diags) {
|
||||
SourceLoc errorLoc = errorExpr->getLoc();
|
||||
switch (reason) {
|
||||
case TypeNotSupported:
|
||||
diags.diagnose(errorLoc, diag::const_unsupported_type);
|
||||
break;
|
||||
case AssociatedValue:
|
||||
diags.diagnose(errorLoc, diag::const_unsupported_enum_associated_value);
|
||||
break;
|
||||
case UnsupportedBinaryOperator:
|
||||
diags.diagnose(errorLoc, diag::const_unsupported_operator);
|
||||
break;
|
||||
case UnsupportedUnaryOperator:
|
||||
diags.diagnose(errorLoc, diag::const_unsupported_operator);
|
||||
break;
|
||||
case TypeExpression:
|
||||
diags.diagnose(errorLoc, diag::const_unsupported_type_expr);
|
||||
break;
|
||||
case KeyPath:
|
||||
diags.diagnose(errorLoc, diag::const_unsupported_keypath);
|
||||
break;
|
||||
case Closue:
|
||||
diags.diagnose(errorLoc, diag::const_unsupported_closure);
|
||||
break;
|
||||
case OpaqueDeclRef:
|
||||
diags.diagnose(errorLoc, diag::const_opaque_decl_ref);
|
||||
break;
|
||||
case OpaqueFuncDeclRef:
|
||||
diags.diagnose(errorLoc, diag::const_opaque_func_decl_ref);
|
||||
break;
|
||||
case NonConventionCFunc:
|
||||
diags.diagnose(errorLoc, diag::const_non_convention_c_conversion);
|
||||
break;
|
||||
case OpaqueCalleeRef:
|
||||
diags.diagnose(errorLoc, diag::const_opaque_callee);
|
||||
break;
|
||||
case NonConstParameter:
|
||||
diags.diagnose(errorLoc, diag::const_non_const_param);
|
||||
break;
|
||||
case Default:
|
||||
diags.diagnose(errorLoc, diag::const_unknown_default);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool supportedOperator(const ApplyExpr *operatorApplyExpr) {
|
||||
const auto operatorDeclRefExpr =
|
||||
operatorApplyExpr->getFn()->getMemberOperatorRef();
|
||||
if (!operatorDeclRefExpr)
|
||||
return false;
|
||||
|
||||
// Non-stdlib operators are not allowed, for now
|
||||
auto operatorDecl = operatorDeclRefExpr->getDecl();
|
||||
if (!operatorDecl->getModuleContext()->isStdlibModule())
|
||||
return false;
|
||||
|
||||
auto operatorName = operatorDecl->getBaseName();
|
||||
if (!operatorName.isOperator())
|
||||
return false;
|
||||
|
||||
auto operatorIdentifier = operatorName.getIdentifier();
|
||||
if (!operatorIdentifier.isArithmeticOperator() &&
|
||||
!operatorIdentifier.isBitwiseOperator() &&
|
||||
!operatorIdentifier.isShiftOperator() &&
|
||||
!operatorIdentifier.isStandardComparisonOperator())
|
||||
return false;
|
||||
|
||||
// Operators which are not integer or floating point type are not
|
||||
// allowed, for now.
|
||||
auto operatorType = operatorApplyExpr->getType();
|
||||
if (!isIntegerType(operatorType) && !isFloatType(operatorType))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::optional<std::pair<const Expr *, IllegalConstErrorDiagnosis>>
|
||||
checkSupportedInConst(const Expr *expr, const DeclContext *declContext) {
|
||||
SmallVector<const Expr *, 4> expressionsToCheck;
|
||||
expressionsToCheck.push_back(expr);
|
||||
while (!expressionsToCheck.empty()) {
|
||||
const Expr *expr = expressionsToCheck.pop_back_val();
|
||||
// Lookthrough IdentityExpr, Tuple, Array, and InjectIntoOptional
|
||||
// expressions.
|
||||
if (const IdentityExpr *identityExpr = dyn_cast<IdentityExpr>(expr)) {
|
||||
expressionsToCheck.push_back(identityExpr->getSubExpr());
|
||||
continue;
|
||||
}
|
||||
if (const TupleExpr *tupleExpr = dyn_cast<TupleExpr>(expr)) {
|
||||
for (const Expr *element : tupleExpr->getElements())
|
||||
expressionsToCheck.push_back(element);
|
||||
continue;
|
||||
}
|
||||
if (const ArrayExpr *arrayExpr = dyn_cast<ArrayExpr>(expr)) {
|
||||
for (const Expr *element : arrayExpr->getElements())
|
||||
expressionsToCheck.push_back(element);
|
||||
continue;
|
||||
}
|
||||
if (const InjectIntoOptionalExpr *optionalExpr =
|
||||
dyn_cast<InjectIntoOptionalExpr>(expr)) {
|
||||
expressionsToCheck.push_back(optionalExpr->getSubExpr());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure that binary expressions consist of literals, references
|
||||
// to other variables, and supported operators on integer and floating
|
||||
// point types only.
|
||||
if (const BinaryExpr *binaryExpr = dyn_cast<BinaryExpr>(expr)) {
|
||||
if (!supportedOperator(binaryExpr))
|
||||
return std::make_pair(binaryExpr, UnsupportedBinaryOperator);
|
||||
|
||||
expressionsToCheck.push_back(binaryExpr->getLHS());
|
||||
expressionsToCheck.push_back(binaryExpr->getRHS());
|
||||
continue;
|
||||
}
|
||||
if (const PrefixUnaryExpr *unaryExpr = dyn_cast<PrefixUnaryExpr>(expr)) {
|
||||
if (!supportedOperator(unaryExpr))
|
||||
return std::make_pair(unaryExpr, UnsupportedUnaryOperator);
|
||||
|
||||
expressionsToCheck.push_back(unaryExpr->getOperand());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Literal expressions are okay
|
||||
if (isa<LiteralExpr>(expr))
|
||||
continue;
|
||||
|
||||
// Type expressions not supported in `@const` expressions
|
||||
if (isa<TypeExpr>(expr))
|
||||
return std::make_pair(expr, TypeExpression);
|
||||
|
||||
// Keypath expressions not supported in `@const` expressions for now
|
||||
if (isa<KeyPathExpr>(expr))
|
||||
return std::make_pair(expr, KeyPath);
|
||||
|
||||
// Closure expressions are not supported in `@const` expressions
|
||||
// TODO: `@const`-evaluable closures
|
||||
if (isa<AbstractClosureExpr>(expr))
|
||||
return std::make_pair(expr, Closue);
|
||||
|
||||
// Function conversions, as long as the conversion is to a 'convention(c)'
|
||||
// then consider the operand sub-expression
|
||||
if (auto functionConvExpr = dyn_cast<FunctionConversionExpr>(expr)) {
|
||||
if (auto targetFnTy =
|
||||
functionConvExpr->getType()->getAs<AnyFunctionType>()) {
|
||||
if (targetFnTy->getExtInfo().getRepresentation() ==
|
||||
FunctionTypeRepresentation::CFunctionPointer) {
|
||||
expressionsToCheck.push_back(functionConvExpr->getSubExpr());
|
||||
continue;
|
||||
} else {
|
||||
return std::make_pair(expr, NonConventionCFunc);
|
||||
}
|
||||
}
|
||||
return std::make_pair(expr, Default);
|
||||
}
|
||||
|
||||
// Default argument expressions of a function must be ensured to be a
|
||||
// constant by the definition of the function.
|
||||
if (isa<DefaultArgumentExpr>(expr))
|
||||
continue;
|
||||
|
||||
auto checkVarDecl = [&](const VarDecl *varDecl) -> bool {
|
||||
// `@const` variables are always okay, their initializer expressions
|
||||
// will be checked separately, individually.
|
||||
if (varDecl->isConstValue())
|
||||
return true;
|
||||
|
||||
// Non-explicitly-`@const` variables must have an initial value
|
||||
// we can look through.
|
||||
if (!varDecl->hasInitialValue())
|
||||
return false;
|
||||
|
||||
if (auto initExpr = varDecl->getParentInitializer()) {
|
||||
expressionsToCheck.push_back(initExpr);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto checkFuncDecl = [&](const FuncDecl *funcDecl) -> bool {
|
||||
if (funcDecl->hasBody() &&
|
||||
funcDecl->getDeclContext()->getOutermostParentSourceFile() ==
|
||||
declContext->getOutermostParentSourceFile())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Look through to initial value expressions of memeber ref expressions
|
||||
if (const MemberRefExpr *memberRef = dyn_cast<MemberRefExpr>(expr)) {
|
||||
if (VarDecl *memberVarDecl =
|
||||
dyn_cast<VarDecl>(memberRef->getMember().getDecl())) {
|
||||
if (checkVarDecl(memberVarDecl))
|
||||
continue;
|
||||
return std::make_pair(expr, OpaqueDeclRef);
|
||||
}
|
||||
return std::make_pair(expr, OpaqueDeclRef);
|
||||
}
|
||||
|
||||
// Look through to initial value expressions of decl ref expressions
|
||||
if (const DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(expr)) {
|
||||
auto decl = declRef->getDecl();
|
||||
// `@const` paramters are always okay
|
||||
if (auto *paramDecl = dyn_cast<ParamDecl>(decl)) {
|
||||
if (!paramDecl->isConstVal())
|
||||
return std::make_pair(expr, NonConstParameter);
|
||||
continue;
|
||||
}
|
||||
|
||||
// function values
|
||||
if (auto *funcDecl = dyn_cast<FuncDecl>(decl)) {
|
||||
if (checkFuncDecl(funcDecl))
|
||||
continue;
|
||||
return std::make_pair(expr, OpaqueDeclRef);
|
||||
}
|
||||
|
||||
if (const VarDecl *varDecl = dyn_cast<VarDecl>(declRef->getDecl())) {
|
||||
if (checkVarDecl(varDecl))
|
||||
continue;
|
||||
return std::make_pair(expr, OpaqueDeclRef);
|
||||
}
|
||||
return std::make_pair(expr, OpaqueDeclRef);
|
||||
}
|
||||
|
||||
// Otherwise only allow enum cases and function calls
|
||||
if (!isa<ApplyExpr>(expr))
|
||||
return std::make_pair(expr, Default);
|
||||
|
||||
const ApplyExpr *apply = cast<ApplyExpr>(expr);
|
||||
ValueDecl *calledValue = apply->getCalledValue();
|
||||
if (!calledValue)
|
||||
return std::make_pair(expr, OpaqueCalleeRef);
|
||||
|
||||
// If this is an enum case, check that it does not have associated values
|
||||
if (EnumElementDecl *enumCase = dyn_cast<EnumElementDecl>(calledValue)) {
|
||||
if (enumCase->hasAssociatedValues())
|
||||
return std::make_pair(expr, AssociatedValue);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Explicitly support calls to `Int` and `Float` constructors
|
||||
if (ConstructorRefCallExpr *initCallRef =
|
||||
dyn_cast<ConstructorRefCallExpr>(apply->getSemanticFn())) {
|
||||
if (auto type = initCallRef->getType()) {
|
||||
if (auto *funcType = type->getAs<FunctionType>()) {
|
||||
auto resultTy = funcType->getResult();
|
||||
if (isIntegerType(resultTy) || isFloatType(resultTy)) {
|
||||
assert(apply->getArgs()->size() == 1);
|
||||
expressionsToCheck.push_back(apply->getArgs()->getExpr(0));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: calls to `@const` functions
|
||||
// AbstractFunctionDecl *callee =
|
||||
// dyn_cast<AbstractFunctionDecl>(calledValue); if (!callee)
|
||||
// return expr;
|
||||
// if (callee->isConstFunction()) {
|
||||
// for (auto arg : *apply->getArgs())
|
||||
// expressionsToCheck.push_back(arg.getExpr());
|
||||
// }
|
||||
|
||||
return std::make_pair(expr, Default);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Given a call \c callExpr, if some or all of its arguments are required to be
|
||||
/// constants, check the argument expressions.
|
||||
static void verifyConstArguments(const CallExpr *callExpr,
|
||||
const DeclContext *declContext) {
|
||||
ValueDecl *calledDecl = callExpr->getCalledValue();
|
||||
if (!calledDecl || !isa<AbstractFunctionDecl>(calledDecl))
|
||||
return;
|
||||
AbstractFunctionDecl *callee = cast<AbstractFunctionDecl>(calledDecl);
|
||||
SmallVector<unsigned, 4> constArgumentIndices;
|
||||
auto paramList = callee->getParameters();
|
||||
for (unsigned i = 0; i < paramList->size(); ++i) {
|
||||
ParamDecl *param = paramList->get(i);
|
||||
if (param->isConstVal())
|
||||
constArgumentIndices.push_back(i);
|
||||
}
|
||||
if (constArgumentIndices.empty())
|
||||
return;
|
||||
|
||||
// Check that the arguments at the constArgumentIndices are all expressions
|
||||
// consisting of @const-compatible constructs.
|
||||
SmallVector<Expr *, 4> arguments;
|
||||
for (auto arg : *callExpr->getArgs())
|
||||
arguments.push_back(arg.getExpr());
|
||||
|
||||
for (unsigned constantIndex : constArgumentIndices) {
|
||||
assert(constantIndex < arguments.size() &&
|
||||
"constantIndex exceeds the number of arguments to the function");
|
||||
if (auto error =
|
||||
checkSupportedInConst(arguments[constantIndex], declContext)) {
|
||||
diagnoseError(error->first, error->second,
|
||||
declContext->getASTContext().Diags);
|
||||
declContext->getASTContext().Diags.diagnose(
|
||||
arguments[constantIndex]->getLoc(),
|
||||
diag::require_const_arg_for_parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
void swift::diagnoseInvalidConstExpressions(const Expr *expr,
|
||||
const DeclContext *declContext,
|
||||
bool isConstInitExpr) {
|
||||
if (isConstInitExpr) {
|
||||
if (auto error = checkSupportedInConst(expr, declContext))
|
||||
diagnoseError(error->first, error->second,
|
||||
declContext->getASTContext().Diags);
|
||||
} else if (auto *callExpr = dyn_cast<CallExpr>(expr))
|
||||
verifyConstArguments(callExpr, declContext);
|
||||
}
|
||||
@@ -6336,7 +6336,8 @@ static void diagnoseMissingMemberImports(const Expr *E, const DeclContext *DC) {
|
||||
/// Emit diagnostics for syntactic restrictions on a given expression.
|
||||
void swift::performSyntacticExprDiagnostics(const Expr *E,
|
||||
const DeclContext *DC,
|
||||
bool isExprStmt) {
|
||||
bool isExprStmt,
|
||||
bool isConstInitExpr) {
|
||||
auto &ctx = DC->getASTContext();
|
||||
TypeChecker::diagnoseSelfAssignment(E);
|
||||
diagSyntacticUseRestrictions(E, DC, isExprStmt);
|
||||
@@ -6353,6 +6354,9 @@ void swift::performSyntacticExprDiagnostics(const Expr *E,
|
||||
if (ctx.LangOpts.EnableObjCInterop)
|
||||
diagDeprecatedObjCSelectors(DC, E);
|
||||
diagnoseConstantArgumentRequirement(E, DC);
|
||||
if (ctx.LangOpts.hasFeature(Feature::CompileTimeValues) &&
|
||||
!ctx.LangOpts.hasFeature(Feature::CompileTimeValuesPreview))
|
||||
diagnoseInvalidConstExpressions(E, DC, isConstInitExpr);
|
||||
diagUnqualifiedAccessToMethodNamedSelf(E, DC);
|
||||
diagnoseDictionaryLiteralDuplicateKeyEntries(E, DC);
|
||||
diagnoseMissingMemberImports(E, DC);
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace swift {
|
||||
|
||||
/// Emit diagnostics for syntactic restrictions on a given expression.
|
||||
void performSyntacticExprDiagnostics(const Expr *E, const DeclContext *DC,
|
||||
bool isExprStmt);
|
||||
bool isExprStmt, bool isConstInitExpr);
|
||||
|
||||
/// Emit diagnostics for a given statement.
|
||||
void performStmtDiagnostics(const Stmt *S, DeclContext *DC);
|
||||
@@ -101,6 +101,13 @@ namespace swift {
|
||||
void diagnoseConstantArgumentRequirement(const Expr *expr,
|
||||
const DeclContext *declContext);
|
||||
|
||||
/// If \p expr is a `@const` expression which contains values and
|
||||
/// operations that are not legal in a `@const` expression,
|
||||
/// emit an error diagnostic.
|
||||
void diagnoseInvalidConstExpressions(const Expr *expr,
|
||||
const DeclContext *declContext,
|
||||
bool isConstInitExpr);
|
||||
|
||||
/// Attempt to fix the type of \p decl so that it's a valid override for
|
||||
/// \p base...but only if we're highly confident that we know what the user
|
||||
/// should have written.
|
||||
|
||||
@@ -339,7 +339,16 @@ public:
|
||||
// closures.
|
||||
if (ExprDepth == 0) {
|
||||
auto isExprStmt = (E == Target.getAsExpr()) ? IsTopLevelExprStmt : false;
|
||||
performSyntacticExprDiagnostics(E, Target.getDeclContext(), isExprStmt);
|
||||
|
||||
bool isConstInitExpr = false;
|
||||
if (Target.isForInitialization()) {
|
||||
if (auto initPattern = Target.getInitializationPattern())
|
||||
if (auto namedPatternVarDecl = initPattern->getSingleVar())
|
||||
isConstInitExpr = namedPatternVarDecl->isConstValue();
|
||||
}
|
||||
|
||||
performSyntacticExprDiagnostics(E, Target.getDeclContext(), isExprStmt,
|
||||
isConstInitExpr);
|
||||
}
|
||||
ExprDepth += 1;
|
||||
return Action::Continue(E);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// Constant globals should "work" when referencing C-imported constants
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146952876
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %t/main.swift -parse-as-library -import-bridging-header %t/bridging_header.h -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %t/main.swift -parse-as-library -import-bridging-header %t/bridging_header.h -enable-experimental-feature CompileTimeValues
|
||||
|
||||
//--- bridging_header.h
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Constant globals on comparisons and conditions
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146953097
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let constGlobal1: Int = true ? 1 : 0
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Constant globals should "work" even when used across files in non-WMO builds.
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-ir -I %t %t/Main.swift -verify -enable-experimental-feature CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -I %t %t/Main.swift -verify -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
|
||||
//--- MyModule.swift
|
||||
|
||||
|
||||
20
test/ConstValues/DiagModulesSyntactic.swift
Normal file
20
test/ConstValues/DiagModulesSyntactic.swift
Normal file
@@ -0,0 +1,20 @@
|
||||
// Constant globals should "work" even when used across files in non-WMO builds.
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-ir -I %t %t/Main.swift -verify -enable-experimental-feature CompileTimeValues
|
||||
|
||||
//--- MyModule.swift
|
||||
|
||||
public func foo() -> Int {
|
||||
return 42
|
||||
}
|
||||
|
||||
//--- Main.swift
|
||||
|
||||
import MyModule
|
||||
|
||||
@const let constGlobal1: Int = foo()
|
||||
// expected-error@-1 {{not supported in a '@const' expression}}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Constant globals rejected for not being constant values
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -verify -enable-experimental-feature CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -verify -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
|
||||
@const let a: Bool = Bool.random()
|
||||
// expected-error@-1 {{'@const' value should be initialized with a compile-time value}}
|
||||
|
||||
13
test/ConstValues/DiagNotConstSyntactic.swift
Normal file
13
test/ConstValues/DiagNotConstSyntactic.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
// Constant globals rejected for not being constant values
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -verify -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let a: Bool = Bool.random()
|
||||
// expected-error@-1 {{not supported in a '@const' expression}}
|
||||
|
||||
func foo() -> Int {
|
||||
return 42 * Int.random(in: 0 ..< 10)
|
||||
}
|
||||
|
||||
@const let b: Int = foo()
|
||||
// expected-error@-1 {{not supported in a '@const' expression}}
|
||||
@@ -1,6 +1,8 @@
|
||||
// Constant globals referencing other constant globals and forming a cycle
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146957382
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -verify -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -verify -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let a: Int = c
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Constant globals on simple floating-point literals
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let constGlobal1 = 42.0
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Constant globals on function types / function pointers
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
|
||||
func foo_void_to_void() {}
|
||||
func foo_int_to_int(x: Int) -> Int { return 42 }
|
||||
|
||||
30
test/ConstValues/FunctionTypesSyntactic.swift
Normal file
30
test/ConstValues/FunctionTypesSyntactic.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
// Constant globals on function types / function pointers
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -verify
|
||||
|
||||
func foo_void_to_void() {}
|
||||
func foo_int_to_int(x: Int) -> Int { return 42 }
|
||||
|
||||
@const let constGlobalA1: ()->() = { }
|
||||
// expected-error@-1{{closures not supported in a '@const' expression}}
|
||||
@const let constGlobalA2: @convention(c) ()->() = { }
|
||||
// expected-error@-1{{closures not supported in a '@const' expression}}
|
||||
@const let constGlobalA3: @convention(thin) ()->() = { }
|
||||
// expected-error@-1{{only 'convention(c)' function values are supported in a '@const' expression}}
|
||||
|
||||
@const let constGlobalB1: ()->() = foo_void_to_void // TODO: Diagnose the type of the variable as not eligigle for '@const' (not the init expression)
|
||||
@const let constGlobalB2: @convention(c) ()->() = foo_void_to_void
|
||||
@const let constGlobalB3: @convention(thin) ()->() = foo_void_to_void
|
||||
// expected-error@-1{{only 'convention(c)' function values are supported in a '@const' expression}}
|
||||
|
||||
@const let constGlobalC1: (Int)->(Int) = { _ in return 42 }
|
||||
// expected-error@-1{{closures not supported in a '@const' expression}}
|
||||
@const let constGlobalC2: @convention(c) (Int)->(Int) = { _ in return 42 }
|
||||
// expected-error@-1{{closures not supported in a '@const' expression}}
|
||||
@const let constGlobalC3: @convention(thin) (Int)->(Int) = { _ in return 42 }
|
||||
// expected-error@-1{{only 'convention(c)' function values are supported in a '@const' expression}}
|
||||
|
||||
@const let constGlobalD1: (Int)->(Int) = foo_int_to_int
|
||||
@const let constGlobalD2: @convention(c) (Int)->(Int) = foo_int_to_int
|
||||
@const let constGlobalD3: @convention(thin) (Int)->(Int) = foo_int_to_int
|
||||
// expected-error@-1{{only 'convention(c)' function values are supported in a '@const' expression}}
|
||||
@@ -1,6 +1,8 @@
|
||||
// Constant globals on inline arrays
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146954768
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -disable-availability-checking -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -disable-availability-checking -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let constGlobal1: InlineArray = [1, 2, 3]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Constant globals on integer arithmetics
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let constGlobal1: Int = 42
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Constant globals on integer expressions
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: optimized_stdlib
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -verify
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview -verify
|
||||
|
||||
@const let constGlobal1: Int = (42 + 42 + 42) / 3
|
||||
@const let constGlobal2: Int = MemoryLayout<UInt32>.size + 4
|
||||
|
||||
11
test/ConstValues/IntegerExpressionsSyntactic.swift
Normal file
11
test/ConstValues/IntegerExpressionsSyntactic.swift
Normal file
@@ -0,0 +1,11 @@
|
||||
// Constant globals on integer expressions
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: optimized_stdlib
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -verify
|
||||
|
||||
@const let constGlobal1: Int = (42 + 42 + 42) / 3
|
||||
@const let constGlobal2: Int = MemoryLayout<UInt32>.size + 4
|
||||
// expected-error@-1{{in a '@const' expression}}
|
||||
@const let constGlobal3: Int = Int(17.0 / 3.5)
|
||||
@const let constGlobal4: Int = constGlobal1 + 1
|
||||
@const let constGlobal5: Int = -constGlobal1 + 1
|
||||
@@ -1,5 +1,7 @@
|
||||
// Constant globals on simple integer literals
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -verify -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -verify -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let constGlobal1: Int = 42
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// Constant values should be able to call "const" functions from other modules
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146953110
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -I %t %t/Main.swift -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-ir -I %t %t/Main.swift -enable-experimental-feature CompileTimeValues
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Constant globals referencing other constant globals in their initializer expressions
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146954110
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let a: Int = 42
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// Constant globals should "work" even when used across files in non-WMO builds.
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146405994
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s/file1.swift -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s/file1.swift -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
//--- file1.swift
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Constant globals on optionals
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let constGlobal1: Int? = 42
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Constant globals on simple integer literals
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-sil -primary-file %s -verify -enable-experimental-feature CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-sil -primary-file %s -verify -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
|
||||
func bar(@const _ thing: UInt) -> UInt {
|
||||
return thing
|
||||
@@ -15,4 +16,3 @@ func foo() {
|
||||
let _ = bar(UInt.random(in: 0..<10))
|
||||
// expected-error@-1 {{expected a compile-time value argument for a '@const' parameter}}
|
||||
}
|
||||
|
||||
|
||||
18
test/ConstValues/ParametersSyntactic.swift
Normal file
18
test/ConstValues/ParametersSyntactic.swift
Normal file
@@ -0,0 +1,18 @@
|
||||
// Constant globals on simple integer literals
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-sil -primary-file %s -verify -enable-experimental-feature CompileTimeValues
|
||||
|
||||
func bar(@const _ thing: UInt) -> UInt {
|
||||
return thing
|
||||
}
|
||||
|
||||
func foo() {
|
||||
let _ = bar(42)
|
||||
let _ = bar(0xf000f000)
|
||||
#if _pointerBitWidth(_64)
|
||||
let _ = bar(0xf000f000_f000f000)
|
||||
#endif
|
||||
let _ = bar(UInt.random(in: 0..<10))
|
||||
// expected-error@-1 {{expected a compile-time value argument for a '@const' parameter}}
|
||||
// expected-error@-2 {{not supported in a '@const' expression}}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
// Constant globals referencing other constant globals in their initializer expressions
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let a: Int = 42
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Constant globals on tuples
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146953330
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let constGlobalStringTuple: (Int, String) = (42, "Foo")
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Constant globals on strings
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146953748
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
@const let constGlobal1: String = "hello"
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// Constant globals should "work" even in top-level code mode.
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// REQUIRES: rdar146954355
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -enable-experimental-feature CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
|
||||
|
||||
@const let constGlobal: Int = 42
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
// Constant globals on tuples
|
||||
// REQUIRES: swift_feature_CompileTimeValues
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues
|
||||
// REQUIRES: swift_feature_CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -enable-experimental-feature CompileTimeValuesPreview
|
||||
// RUN: %target-swift-frontend -emit-ir -primary-file %s -parse-as-library -enable-experimental-feature CompileTimeValues -verify
|
||||
|
||||
@const let constGlobal1: Int = 42
|
||||
@const let constGlobal2: (Int, Int) = (42, 42)
|
||||
@const let constGlobal3: (Int, Bool) = (42, true)
|
||||
@const let constGlobal4: (Int, (Int, Int)) = (42, (42, 42))
|
||||
@const let constGlobal5: (Int, Float) = (42, 42.0)
|
||||
@const let constGlobal7: (UInt64, StaticString, @convention(c) ()->Int) = (42, "hi", { return 42 })
|
||||
|
||||
// Closure call not supported in syntactically-validated mode
|
||||
@const let constGlobal7: (UInt64, StaticString, @convention(c) ()->Int) = (42, "hi", { return 42 }) // expected-error {{not supported in a '@const' expression}}
|
||||
|
||||
@@ -21,12 +21,11 @@ func takeIntConst(@const _ a: Int) {}
|
||||
struct Article {
|
||||
let id: String
|
||||
}
|
||||
@const let keypath = \Article.id
|
||||
@const let keypath = \Article.id // expected-error{{keypaths not supported in a '@const' expression}}
|
||||
|
||||
func LocalConstVarUser() -> Int {
|
||||
@const let localConst = 3
|
||||
return localConst + 1
|
||||
}
|
||||
|
||||
// FIXME: This should be diagnosed
|
||||
@const let a: Bool = Bool.random()
|
||||
@const let a: Bool = Bool.random() // expected-error{{not supported in a '@const' expression}}
|
||||
|
||||
Reference in New Issue
Block a user