Skip to content

Commit db53a37

Browse files
Merge pull request swiftlang#32908 from ravikandhadai/SwiftUIPreviewFix-5.3
[Sema][os_log] Allow wrapping os_log strings within constant evaluable functions
2 parents 62efa55 + d827f58 commit db53a37

File tree

3 files changed

+84
-8
lines changed

3 files changed

+84
-8
lines changed

lib/Sema/ConstantnessSemaDiagnostics.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ static bool hasConstantEvaluableAttr(ValueDecl *decl) {
9292
return hasSemanticsAttr(decl, semantics::CONSTANT_EVALUABLE);
9393
}
9494

95+
/// Return true iff the \p decl is annotated with oslog.message.init semantics
96+
/// attribute.
97+
static bool isOSLogMessageInitializer(ValueDecl *decl) {
98+
return hasSemanticsAttr(decl, semantics::OSLOG_MESSAGE_INIT_STRING_LITERAL) ||
99+
hasSemanticsAttr(decl, semantics::OSLOG_MESSAGE_INIT_INTERPOLATION);
100+
}
101+
95102
/// Check whether \p expr is a compile-time constant. It must either be a
96103
/// literal_expr, which does not include array and dictionary literal, or a
97104
/// closure expression, which is considered a compile-time constant of a
@@ -162,12 +169,6 @@ static Expr *checkConstantness(Expr *expr) {
162169
if (!isa<ApplyExpr>(expr))
163170
return expr;
164171

165-
if (NominalTypeDecl *nominal =
166-
expr->getType()->getNominalOrBoundGenericNominal()) {
167-
if (nominal->getName() == nominal->getASTContext().Id_OSLogMessage)
168-
return expr;
169-
}
170-
171172
ApplyExpr *apply = cast<ApplyExpr>(expr);
172173
ValueDecl *calledValue = apply->getCalledValue();
173174
if (!calledValue)
@@ -179,10 +180,18 @@ static Expr *checkConstantness(Expr *expr) {
179180
continue;
180181
}
181182

183+
AbstractFunctionDecl *callee = dyn_cast<AbstractFunctionDecl>(calledValue);
184+
if (!callee)
185+
return expr;
186+
187+
// If this is an application of OSLogMessage initializer, fail the check
188+
// as this type must be created from string interpolations.
189+
if (isOSLogMessageInitializer(callee))
190+
return expr;
191+
182192
// If this is a constant_evaluable function, check whether the arguments are
183193
// constants.
184-
AbstractFunctionDecl *callee = dyn_cast<AbstractFunctionDecl>(calledValue);
185-
if (!callee || !hasConstantEvaluableAttr(callee))
194+
if (!hasConstantEvaluableAttr(callee))
186195
return expr;
187196
expressionsToCheck.push_back(apply->getArg());
188197
}

test/SILOptimizer/OSLogMandatoryOptTest.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,41 @@ extension TestProtocolSelfTypeCapture {
635635
}
636636
}
637637

638+
// Test that SwiftUI's preview transformations work with the logging APIs.
639+
640+
// A function similar to the one used by SwiftUI preview to wrap string
641+
// literals.
642+
@_semantics("constant_evaluable")
643+
@_transparent
644+
public func __designTimeStringStub(
645+
_ key: String,
646+
fallback: OSLogMessage
647+
) -> OSLogMessage {
648+
fallback
649+
}
650+
651+
// CHECK-LABEL: @${{.*}}testSwiftUIPreviewWrappingyy
652+
func testSwiftUIPreviewWrapping() {
653+
_osLogTestHelper(__designTimeStringStub("key", fallback: "percent: %"))
654+
// CHECK: string_literal utf8 "percent: %%"
655+
// CHECK-NOT: OSLogMessage
656+
// CHECK-NOT: OSLogInterpolation
657+
// CHECK-LABEL: end sil function '${{.*}}testSwiftUIPreviewWrappingyy
658+
}
659+
660+
661+
func functionTakingClosure(_ x: () -> Void) { }
662+
663+
func testWrappingWithinClosures(x: Int) {
664+
functionTakingClosure {
665+
_osLogTestHelper(
666+
__designTimeStringStub(
667+
"key",
668+
fallback: "escaping of percent: %"))
669+
// CHECK-LABEL: @${{.*}}testWrappingWithinClosures1xySi_tFyyXEfU_
670+
// CHECK: string_literal utf8 "escaping of percent: %%"
671+
// CHECK-NOT: OSLogMessage
672+
// CHECK-NOT: OSLogInterpolation
673+
// CHECK-LABEL: end sil function '${{.*}}testWrappingWithinClosures1xySi_tFyyXEfU_
674+
}
675+
}

test/Sema/diag_constantness_check_os_log.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,32 @@ func testNonConstantLogObjectLevel(
155155
osLogWithLevel(level, log: log, message)
156156
// expected-error@-1 {{argument must be a string interpolation}}
157157
}
158+
159+
// Test that log messages can be wrapped in constant_evaluable functions.
160+
161+
// A function similar to the one used by SwiftUI preview to wrap string
162+
// literals.
163+
@_semantics("constant_evaluable")
164+
public func __designTimeStringStub(
165+
_ key: String,
166+
fallback: OSLogMessage
167+
) -> OSLogMessage {
168+
fallback
169+
}
170+
171+
func testSwiftUIPreviewWrapping() {
172+
// This should not produce any diagnostics.
173+
_osLogTestHelper(__designTimeStringStub("key", fallback: "A literal message"))
174+
}
175+
176+
public func nonConstantFunction(
177+
_ key: String,
178+
fallback: OSLogMessage
179+
) -> OSLogMessage {
180+
fallback
181+
}
182+
183+
func testLogMessageWrappingDiagnostics() {
184+
_osLogTestHelper(nonConstantFunction("key", fallback: "A literal message"))
185+
// expected-error@-1{{argument must be a string interpolation}}
186+
}

0 commit comments

Comments
 (0)