Skip to content

Commit b0c8cdc

Browse files
authored
Merge pull request #1853 from swiftwasm/main
[pull] swiftwasm from main
2 parents 42594db + f8f40e0 commit b0c8cdc

File tree

5 files changed

+130
-2
lines changed

5 files changed

+130
-2
lines changed

lib/SILGen/SILGenConstructor.cpp

+18-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "SILGenFunctionBuilder.h"
1919
#include "Scope.h"
2020
#include "swift/AST/ASTMangler.h"
21+
#include "swift/AST/ForeignErrorConvention.h"
2122
#include "swift/AST/GenericEnvironment.h"
2223
#include "swift/AST/ParameterList.h"
2324
#include "swift/AST/PropertyWrappers.h"
@@ -211,8 +212,24 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
211212
"number of args does not match number of fields");
212213
(void)eltEnd;
213214
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
215+
216+
RValue arg = std::move(*elti);
217+
218+
// If the stored property has an attached function builder and its
219+
// type is not a function type, the argument is a noescape closure
220+
// that needs to be called.
221+
if (field->getFunctionBuilderType()) {
222+
if (!field->getValueInterfaceType()
223+
->lookThroughAllOptionalTypes()->is<AnyFunctionType>()) {
224+
auto resultTy = cast<FunctionType>(arg.getType()).getResult();
225+
arg = SGF.emitMonomorphicApply(
226+
Loc, std::move(arg).getAsSingleValue(SGF, Loc), { }, resultTy,
227+
resultTy, ApplyOptions::None, None, None);
228+
}
229+
}
230+
214231
maybeEmitPropertyWrapperInitFromValue(SGF, Loc, field, subs,
215-
std::move(*elti))
232+
std::move(arg))
216233
.forwardInto(SGF, Loc, init.get());
217234
++elti;
218235
} else {

lib/Sema/CodeSynthesis.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,20 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
261261
}
262262
}
263263

264+
Type functionBuilderType= var->getFunctionBuilderType();
265+
if (functionBuilderType) {
266+
// If the variable's type is structurally a function type, use that
267+
// type. Otherwise, form a non-escaping function type for the function
268+
// parameter.
269+
bool isStructuralFunctionType =
270+
varInterfaceType->lookThroughAllOptionalTypes()
271+
->is<AnyFunctionType>();
272+
if (!isStructuralFunctionType) {
273+
auto extInfo = ASTExtInfoBuilder().withNoEscape().build();
274+
varInterfaceType = FunctionType::get({ }, varInterfaceType, extInfo);
275+
}
276+
}
277+
264278
// Create the parameter.
265279
auto *arg = new (ctx)
266280
ParamDecl(SourceLoc(), Loc,
@@ -273,6 +287,14 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
273287
// Don't allow the parameter to accept temporary pointer conversions.
274288
arg->setNonEphemeralIfPossible();
275289

290+
// Attach a function builder attribute if needed.
291+
if (functionBuilderType) {
292+
auto typeExpr = TypeExpr::createImplicit(functionBuilderType, ctx);
293+
auto attr = CustomAttr::create(
294+
ctx, SourceLoc(), typeExpr, /*implicit=*/true);
295+
arg->getAttrs().add(attr);
296+
}
297+
276298
maybeAddMemberwiseDefaultArg(arg, var, params.size(), ctx);
277299

278300
params.push_back(arg);

lib/Sema/TypeCheckAttr.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -2987,8 +2987,19 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
29872987
} else if (auto storage = dyn_cast<AbstractStorageDecl>(D)) {
29882988
decl = storage;
29892989

2990-
// Check whether this is a property without an explicit getter.
2990+
// Check whether this is a storage declaration that is not permitted
2991+
// to have a function builder attached.
29912992
auto shouldDiagnose = [&]() -> bool {
2993+
// An uninitialized stored property in a struct can have a function
2994+
// builder attached.
2995+
if (auto var = dyn_cast<VarDecl>(decl)) {
2996+
if (var->isInstanceMember() &&
2997+
isa<StructDecl>(var->getDeclContext()) &&
2998+
!var->getParentInitializer()) {
2999+
return false;
3000+
}
3001+
}
3002+
29923003
auto getter = storage->getParsedAccessor(AccessorKind::Get);
29933004
if (!getter)
29943005
return true;

test/Constraints/function_builder.swift

+21
Original file line numberDiff line numberDiff line change
@@ -767,3 +767,24 @@ do {
767767
} catch {
768768
fatalError("Threw something else?")
769769
}
770+
771+
// CHECK: testStoredProperties
772+
struct MyTupleStruct<T, U> {
773+
@TupleBuilder let first: () -> T
774+
@TupleBuilder let second: U
775+
}
776+
777+
print("testStoredProperties")
778+
let ts1 = MyTupleStruct {
779+
1
780+
"hello"
781+
if true {
782+
"conditional"
783+
}
784+
} second: {
785+
3.14159
786+
"blah"
787+
}
788+
789+
// CHECK: MyTupleStruct<(Int, String, Optional<String>), (Double, String)>(first: (Function), second: (3.14159, "blah"))
790+
print(ts1)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
@_functionBuilder
4+
struct TupleBuilder {
5+
static func buildBlock<T1>(_ t1: T1) -> (T1) {
6+
return (t1)
7+
}
8+
9+
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
10+
return (t1, t2)
11+
}
12+
13+
static func buildBlock<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3)
14+
-> (T1, T2, T3) {
15+
return (t1, t2, t3)
16+
}
17+
18+
static func buildBlock<T1, T2, T3, T4>(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4)
19+
-> (T1, T2, T3, T4) {
20+
return (t1, t2, t3, t4)
21+
}
22+
23+
static func buildBlock<T1, T2, T3, T4, T5>(
24+
_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5
25+
) -> (T1, T2, T3, T4, T5) {
26+
return (t1, t2, t3, t4, t5)
27+
}
28+
29+
static func buildOptional<T>(_ value: T?) -> T? { return value }
30+
}
31+
32+
struct MyTupleStruct<T, U> {
33+
@TupleBuilder let first: () -> T
34+
@TupleBuilder let second: U
35+
// CHECK: init(@TupleBuilder first: @escaping () -> T, @TupleBuilder second: () -> U)
36+
}
37+
38+
// CHECK-LABEL: sil hidden [ossa] @$s27function_builder_memberwise13MyTupleStructV5first6secondACyxq_Gxyc_q_yXEtcfC : $@convention(method) <T, U> (@owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T>, @noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <U>, @thin MyTupleStruct<T, U>.Type) -> @out MyTupleStruct<T, U> {
39+
// CHECK: bb0([[SELF:%.*]] : $*MyTupleStruct<T, U>, [[FIRST:%.*]] : @owned $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T>, [[SECOND:%.*]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <U>, [[META:%.*]] : $@thin MyTupleStruct<T, U>.Type):
40+
// CHECK-NEXT: [[FIRST_ADDR:%.*]] = struct_element_addr [[SELF]] : $*MyTupleStruct<T, U>, #MyTupleStruct.first
41+
// CHECK-NEXT: store [[FIRST]] to [init] [[FIRST_ADDR]] : $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T>
42+
// CHECK-NEXT: [[SECOND_ADDR:%.*]] = struct_element_addr [[SELF]] : $*MyTupleStruct<T, U>, #MyTupleStruct.second
43+
// CHECK-NEXT: [[CALL_RESULT:%.*]] = alloc_stack $U
44+
// CHECK-NEXT: apply [[SECOND]]([[CALL_RESULT]]) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <U>
45+
// CHECK-NEXT: copy_addr [take] [[CALL_RESULT]] to [initialization] [[SECOND_ADDR]] : $*U
46+
func trigger(cond: Bool) {
47+
_ = MyTupleStruct {
48+
1
49+
"hello"
50+
if cond {
51+
"conditional"
52+
}
53+
} second: {
54+
3.14159
55+
"blah"
56+
}
57+
}

0 commit comments

Comments
 (0)