From d8176a7e89e36dd99eb3d427a264c9042f1eec7c Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 15 Apr 2025 15:37:02 -0700 Subject: [PATCH] [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 --- include/swift/AST/DiagnosticsSema.def | 27 +- include/swift/Basic/Features.def | 3 + lib/AST/FeatureSet.cpp | 4 + lib/Sema/CMakeLists.txt | 1 + lib/Sema/CSDiagnostics.cpp | 2 +- lib/Sema/LegalConstExprVerifier.cpp | 379 ++++++++++++++++++ lib/Sema/MiscDiagnostics.cpp | 6 +- lib/Sema/MiscDiagnostics.h | 9 +- lib/Sema/TypeCheckConstraints.cpp | 11 +- test/ConstValues/CImports.swift | 2 + test/ConstValues/Conditions.swift | 2 + test/ConstValues/DiagModules.swift | 5 +- test/ConstValues/DiagModulesSyntactic.swift | 20 + test/ConstValues/DiagNotConst.swift | 3 +- test/ConstValues/DiagNotConstSyntactic.swift | 13 + test/ConstValues/DiagReferenceCycle.swift | 2 + test/ConstValues/FloatintPointLiterals.swift | 2 + test/ConstValues/FunctionTypes.swift | 3 +- test/ConstValues/FunctionTypesSyntactic.swift | 30 ++ test/ConstValues/InlineArrays.swift | 2 + test/ConstValues/IntegerArithmetic.swift | 2 + test/ConstValues/IntegerExpressions.swift | 3 +- .../IntegerExpressionsSyntactic.swift | 11 + test/ConstValues/IntegerLiterals.swift | 2 + test/ConstValues/Modules.swift | 4 + test/ConstValues/NegativeUnaryReference.swift | 2 + test/ConstValues/NonWMO.swift | 2 + test/ConstValues/Optionals.swift | 2 + test/ConstValues/Parameters.swift | 4 +- test/ConstValues/ParametersSyntactic.swift | 18 + test/ConstValues/References.swift | 2 + test/ConstValues/StringTuples.swift | 2 + test/ConstValues/Strings.swift | 2 + test/ConstValues/TopLevel.swift | 5 +- test/ConstValues/Tuples.swift | 8 +- test/Parse/const.swift | 5 +- 36 files changed, 582 insertions(+), 18 deletions(-) create mode 100644 lib/Sema/LegalConstExprVerifier.cpp create mode 100644 test/ConstValues/DiagModulesSyntactic.swift create mode 100644 test/ConstValues/DiagNotConstSyntactic.swift create mode 100644 test/ConstValues/FunctionTypesSyntactic.swift create mode 100644 test/ConstValues/IntegerExpressionsSyntactic.swift create mode 100644 test/ConstValues/ParametersSyntactic.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index aed6f1368ec..6126ba75130 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -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 //------------------------------------------------------------------------------ diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index ac2a9ad29e4..1d879689c9a 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -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) diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index 9a9eee441b7..e366ab63b19 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -408,6 +408,10 @@ static bool usesFeatureCompileTimeValues(Decl *decl) { decl->getAttrs().hasAttribute(); } +static bool usesFeatureCompileTimeValuesPreview(Decl *decl) { + return false; +} + static bool usesFeatureClosureBodyMacro(Decl *decl) { return false; } diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index f82750f1339..84ae48ce0f6 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -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 diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 821a3168b4f..bc0a01ae4b9 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.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; } diff --git a/lib/Sema/LegalConstExprVerifier.cpp b/lib/Sema/LegalConstExprVerifier.cpp new file mode 100644 index 00000000000..76dee5ac9a9 --- /dev/null +++ b/lib/Sema/LegalConstExprVerifier.cpp @@ -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> +checkSupportedInConst(const Expr *expr, const DeclContext *declContext) { + SmallVector 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(expr)) { + expressionsToCheck.push_back(identityExpr->getSubExpr()); + continue; + } + if (const TupleExpr *tupleExpr = dyn_cast(expr)) { + for (const Expr *element : tupleExpr->getElements()) + expressionsToCheck.push_back(element); + continue; + } + if (const ArrayExpr *arrayExpr = dyn_cast(expr)) { + for (const Expr *element : arrayExpr->getElements()) + expressionsToCheck.push_back(element); + continue; + } + if (const InjectIntoOptionalExpr *optionalExpr = + dyn_cast(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(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(expr)) { + if (!supportedOperator(unaryExpr)) + return std::make_pair(unaryExpr, UnsupportedUnaryOperator); + + expressionsToCheck.push_back(unaryExpr->getOperand()); + continue; + } + + // Literal expressions are okay + if (isa(expr)) + continue; + + // Type expressions not supported in `@const` expressions + if (isa(expr)) + return std::make_pair(expr, TypeExpression); + + // Keypath expressions not supported in `@const` expressions for now + if (isa(expr)) + return std::make_pair(expr, KeyPath); + + // Closure expressions are not supported in `@const` expressions + // TODO: `@const`-evaluable closures + if (isa(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(expr)) { + if (auto targetFnTy = + functionConvExpr->getType()->getAs()) { + 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(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(expr)) { + if (VarDecl *memberVarDecl = + dyn_cast(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(expr)) { + auto decl = declRef->getDecl(); + // `@const` paramters are always okay + if (auto *paramDecl = dyn_cast(decl)) { + if (!paramDecl->isConstVal()) + return std::make_pair(expr, NonConstParameter); + continue; + } + + // function values + if (auto *funcDecl = dyn_cast(decl)) { + if (checkFuncDecl(funcDecl)) + continue; + return std::make_pair(expr, OpaqueDeclRef); + } + + if (const VarDecl *varDecl = dyn_cast(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(expr)) + return std::make_pair(expr, Default); + + const ApplyExpr *apply = cast(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(calledValue)) { + if (enumCase->hasAssociatedValues()) + return std::make_pair(expr, AssociatedValue); + continue; + } + + // Explicitly support calls to `Int` and `Float` constructors + if (ConstructorRefCallExpr *initCallRef = + dyn_cast(apply->getSemanticFn())) { + if (auto type = initCallRef->getType()) { + if (auto *funcType = type->getAs()) { + 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(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(calledDecl)) + return; + AbstractFunctionDecl *callee = cast(calledDecl); + SmallVector 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 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(expr)) + verifyConstArguments(callExpr, declContext); +} diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index be036a626d8..b8a57aab119 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -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); diff --git a/lib/Sema/MiscDiagnostics.h b/lib/Sema/MiscDiagnostics.h index 36f24c71dfb..32289fbb432 100644 --- a/lib/Sema/MiscDiagnostics.h +++ b/lib/Sema/MiscDiagnostics.h @@ -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. diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 36f3790d719..08fece6df3c 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -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); diff --git a/test/ConstValues/CImports.swift b/test/ConstValues/CImports.swift index c134dc4366b..ee19dfc6e9c 100644 --- a/test/ConstValues/CImports.swift +++ b/test/ConstValues/CImports.swift @@ -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 diff --git a/test/ConstValues/Conditions.swift b/test/ConstValues/Conditions.swift index 74ebc9212da..b30bb152d87 100644 --- a/test/ConstValues/Conditions.swift +++ b/test/ConstValues/Conditions.swift @@ -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 diff --git a/test/ConstValues/DiagModules.swift b/test/ConstValues/DiagModules.swift index e663b21270f..33693e93208 100644 --- a/test/ConstValues/DiagModules.swift +++ b/test/ConstValues/DiagModules.swift @@ -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 diff --git a/test/ConstValues/DiagModulesSyntactic.swift b/test/ConstValues/DiagModulesSyntactic.swift new file mode 100644 index 00000000000..742b65fffba --- /dev/null +++ b/test/ConstValues/DiagModulesSyntactic.swift @@ -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}} diff --git a/test/ConstValues/DiagNotConst.swift b/test/ConstValues/DiagNotConst.swift index 4f078b8aa4c..177eaf7cff4 100644 --- a/test/ConstValues/DiagNotConst.swift +++ b/test/ConstValues/DiagNotConst.swift @@ -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}} diff --git a/test/ConstValues/DiagNotConstSyntactic.swift b/test/ConstValues/DiagNotConstSyntactic.swift new file mode 100644 index 00000000000..8d522281f4b --- /dev/null +++ b/test/ConstValues/DiagNotConstSyntactic.swift @@ -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}} diff --git a/test/ConstValues/DiagReferenceCycle.swift b/test/ConstValues/DiagReferenceCycle.swift index 84513b950a9..8d1501deeed 100644 --- a/test/ConstValues/DiagReferenceCycle.swift +++ b/test/ConstValues/DiagReferenceCycle.swift @@ -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 diff --git a/test/ConstValues/FloatintPointLiterals.swift b/test/ConstValues/FloatintPointLiterals.swift index 50dd59adc20..54bc41037f3 100644 --- a/test/ConstValues/FloatintPointLiterals.swift +++ b/test/ConstValues/FloatintPointLiterals.swift @@ -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 diff --git a/test/ConstValues/FunctionTypes.swift b/test/ConstValues/FunctionTypes.swift index a087c282737..fc1f5fa0d8c 100644 --- a/test/ConstValues/FunctionTypes.swift +++ b/test/ConstValues/FunctionTypes.swift @@ -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 } diff --git a/test/ConstValues/FunctionTypesSyntactic.swift b/test/ConstValues/FunctionTypesSyntactic.swift new file mode 100644 index 00000000000..3f969f516ac --- /dev/null +++ b/test/ConstValues/FunctionTypesSyntactic.swift @@ -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}} diff --git a/test/ConstValues/InlineArrays.swift b/test/ConstValues/InlineArrays.swift index e6bfa97dcb4..a952bfa7a71 100644 --- a/test/ConstValues/InlineArrays.swift +++ b/test/ConstValues/InlineArrays.swift @@ -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] diff --git a/test/ConstValues/IntegerArithmetic.swift b/test/ConstValues/IntegerArithmetic.swift index 7c47fe68105..33d105e4318 100644 --- a/test/ConstValues/IntegerArithmetic.swift +++ b/test/ConstValues/IntegerArithmetic.swift @@ -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 diff --git a/test/ConstValues/IntegerExpressions.swift b/test/ConstValues/IntegerExpressions.swift index dcfee643f89..28604c91ff9 100644 --- a/test/ConstValues/IntegerExpressions.swift +++ b/test/ConstValues/IntegerExpressions.swift @@ -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.size + 4 diff --git a/test/ConstValues/IntegerExpressionsSyntactic.swift b/test/ConstValues/IntegerExpressionsSyntactic.swift new file mode 100644 index 00000000000..c9ca04662a9 --- /dev/null +++ b/test/ConstValues/IntegerExpressionsSyntactic.swift @@ -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.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 diff --git a/test/ConstValues/IntegerLiterals.swift b/test/ConstValues/IntegerLiterals.swift index 236bd1d3b7d..43d548b8fc6 100644 --- a/test/ConstValues/IntegerLiterals.swift +++ b/test/ConstValues/IntegerLiterals.swift @@ -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 diff --git a/test/ConstValues/Modules.swift b/test/ConstValues/Modules.swift index 29ecf29fe2a..c1f2fd4de06 100644 --- a/test/ConstValues/Modules.swift +++ b/test/ConstValues/Modules.swift @@ -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 diff --git a/test/ConstValues/NegativeUnaryReference.swift b/test/ConstValues/NegativeUnaryReference.swift index ada198b883e..d604c91e2f3 100644 --- a/test/ConstValues/NegativeUnaryReference.swift +++ b/test/ConstValues/NegativeUnaryReference.swift @@ -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 diff --git a/test/ConstValues/NonWMO.swift b/test/ConstValues/NonWMO.swift index 505c3561464..627c19ac6d8 100644 --- a/test/ConstValues/NonWMO.swift +++ b/test/ConstValues/NonWMO.swift @@ -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 diff --git a/test/ConstValues/Optionals.swift b/test/ConstValues/Optionals.swift index 85886f4340a..9ac4a01515c 100644 --- a/test/ConstValues/Optionals.swift +++ b/test/ConstValues/Optionals.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 diff --git a/test/ConstValues/Parameters.swift b/test/ConstValues/Parameters.swift index 6870088d77d..daa24ab86f7 100644 --- a/test/ConstValues/Parameters.swift +++ b/test/ConstValues/Parameters.swift @@ -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}} } - diff --git a/test/ConstValues/ParametersSyntactic.swift b/test/ConstValues/ParametersSyntactic.swift new file mode 100644 index 00000000000..896c7b9f6ad --- /dev/null +++ b/test/ConstValues/ParametersSyntactic.swift @@ -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}} +} diff --git a/test/ConstValues/References.swift b/test/ConstValues/References.swift index 5c2f1518c64..df20f66e695 100644 --- a/test/ConstValues/References.swift +++ b/test/ConstValues/References.swift @@ -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 diff --git a/test/ConstValues/StringTuples.swift b/test/ConstValues/StringTuples.swift index e1225c83bcd..52ed30a3755 100644 --- a/test/ConstValues/StringTuples.swift +++ b/test/ConstValues/StringTuples.swift @@ -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") diff --git a/test/ConstValues/Strings.swift b/test/ConstValues/Strings.swift index 74707ffe0f8..1c69c397646 100644 --- a/test/ConstValues/Strings.swift +++ b/test/ConstValues/Strings.swift @@ -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" diff --git a/test/ConstValues/TopLevel.swift b/test/ConstValues/TopLevel.swift index b6ad2bdbc97..86711c9e718 100644 --- a/test/ConstValues/TopLevel.swift +++ b/test/ConstValues/TopLevel.swift @@ -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 diff --git a/test/ConstValues/Tuples.swift b/test/ConstValues/Tuples.swift index e1026d93799..7bf569da669 100644 --- a/test/ConstValues/Tuples.swift +++ b/test/ConstValues/Tuples.swift @@ -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}} diff --git a/test/Parse/const.swift b/test/Parse/const.swift index b169ec86216..e9ee4521d86 100644 --- a/test/Parse/const.swift +++ b/test/Parse/const.swift @@ -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}}