Skip to content

Commit 1880eb0

Browse files
author
Harlan Haskins
authored
Merge pull request #27004 from harlanhaskins/extremely-default-and-incredibly-nil-5.1
[5.1] [AST] Handle printing default values for tuples of nils
2 parents 3433727 + 5e0aa68 commit 1880eb0

File tree

3 files changed

+153
-1
lines changed

3 files changed

+153
-1
lines changed

lib/AST/Decl.cpp

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5874,6 +5874,46 @@ Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var,
58745874
return initArg;
58755875
}
58765876

5877+
/// Writes a tuple expression where each element is either `nil` or another such
5878+
/// tuple of nils.
5879+
/// This comes up when printing default arguments for memberwise initializers
5880+
/// that were created implicitly.
5881+
/// For example, this var:
5882+
/// ```
5883+
/// var x: (Int?, (Int?, Int?, ()))
5884+
/// ```
5885+
/// will produce `(nil, (nil, nil, ()))`
5886+
static void writeTupleOfNils(TupleType *type, llvm::raw_ostream &os) {
5887+
os << '(';
5888+
for (unsigned i = 0; i < type->getNumElements(); ++i) {
5889+
auto &elt = type->getElement(i);
5890+
if (elt.hasName()) {
5891+
os << elt.getName().str() << ": ";
5892+
}
5893+
5894+
if (elt.getType()->getOptionalObjectType()) {
5895+
os << "nil";
5896+
} else {
5897+
writeTupleOfNils(elt.getType()->castTo<TupleType>(), os);
5898+
}
5899+
if (i < type->getNumElements() - 1) {
5900+
os << ", ";
5901+
}
5902+
}
5903+
os << ')';
5904+
}
5905+
5906+
/// Determines if the given type is a potentially nested tuple of optional
5907+
/// types.
5908+
static bool isTupleOfOptionals(Type type) {
5909+
auto tuple = type->getAs<TupleType>();
5910+
if (!tuple) return false;
5911+
for (auto elt : tuple->getElementTypes())
5912+
if (!elt->getOptionalObjectType() && !isTupleOfOptionals(elt))
5913+
return false;
5914+
return true;
5915+
}
5916+
58775917
StringRef
58785918
ParamDecl::getDefaultValueStringRepresentation(
58795919
SmallVectorImpl<char> &scratch) const {
@@ -5940,8 +5980,24 @@ ParamDecl::getDefaultValueStringRepresentation(
59405980
}
59415981
}
59425982

5983+
auto init = var->getParentInitializer();
5984+
if (!init || !init->getSourceRange().isValid()) {
5985+
// Special case: There are two possible times where we will synthesize a
5986+
// default initial value for a stored property: if the type
5987+
// is Optional, or if it's a (potentially nested) tuple of
5988+
// all Optional elements. If it's Optional, we'll set
5989+
// the DefaultArgumentKind to NilLiteral, but if we're still
5990+
// handling a StoredProperty, then we know it's a tuple.
5991+
if (isTupleOfOptionals(getInterfaceType())) {
5992+
llvm::raw_svector_ostream os(scratch);
5993+
writeTupleOfNils(getInterfaceType()->castTo<TupleType>(), os);
5994+
return os.str();
5995+
}
5996+
return "<<empty>>";
5997+
}
5998+
59435999
return extractInlinableText(getASTContext().SourceMgr,
5944-
var->getParentInitializer(),
6000+
init,
59456001
scratch);
59466002
}
59476003
case DefaultArgumentKind::Inherited: return "super";

test/IDE/print_ast_tc_decls.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,20 @@ class FooClassComputed {
13471347
// PASS_PRINT_AST: }
13481348
}
13491349

1350+
// PASS_PRINT_AST: struct HasDefaultTupleOfNils {
1351+
// PASS_PRINT_AST: var x: (Int?, Int?)
1352+
// PASS_PRINT_AST: var y: Int?
1353+
// PASS_PRINT_AST: var z: Int
1354+
// PASS_PRINT_AST: var w: ((Int?, (), Int?), (Int?, Int?))
1355+
// PASS_PRINT_AST: init(x: (Int?, Int?) = (nil, nil), y: Int? = nil, z: Int, w: ((Int?, (), Int?), (Int?, Int?)) = ((nil, (), nil), (nil, nil)))
1356+
// PASS_PRINT_AST: }
1357+
struct HasDefaultTupleOfNils {
1358+
var x: (Int?, Int?)
1359+
var y: Int?
1360+
var z: Int
1361+
var w: ((Int?, (), Int?), (Int?, Int?))
1362+
}
1363+
13501364
// Protocol extensions
13511365

13521366
protocol ProtocolToExtend {
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// RUN: %target-swift-emit-silgen -module-name implicit_property_initializers -Xllvm -sil-full-demangle -enable-testing %s | %FileCheck %s
2+
3+
// CHECK: struct HasDefaultTupleOfNils {
4+
// CHECK: @_hasStorage @_hasInitialValue var x: (Int?, Int?)
5+
// CHECK: @_hasStorage @_hasInitialValue var y: Int?
6+
// CHECK: @_hasStorage var z: Int
7+
// CHECK: @_hasStorage @_hasInitialValue var w: ((Int?, (), Int?), (Int?, Int?))
8+
// CHECK: init(x: (Int?, Int?) = (nil, nil),
9+
// CHECK-SAME: y: Int? = nil,
10+
// CHECK-SAME: z: Int,
11+
// CHECK-SAME: w: ((Int?, (), Int?), (Int?, Int?)) = ((nil, (), nil), (nil, nil)))
12+
// CHECK: }
13+
struct HasDefaultTupleOfNils {
14+
var x: (Int?, Int?)
15+
var y: Int?
16+
var z: Int
17+
var w: ((Int?, (), Int?), (Int?, Int?))
18+
}
19+
20+
// The default value initializer for 'x' should have type (Optional<Int>, Optional<Int>)
21+
22+
// CHECK: sil [transparent] [ossa] @$[[X_VALUE_INIT:s30implicit_property_initializers21HasDefaultTupleOfNilsV1xSiSg_AEtvpfi]] : $@convention(thin) () -> (Optional<Int>, Optional<Int>) {
23+
// CHECK: bb0:
24+
// CHECK: %[[OPT1:[0-9]+]] = enum $Optional<Int>, #Optional.none!enumelt
25+
// CHECK: %[[OPT2:[0-9]+]] = enum $Optional<Int>, #Optional.none!enumelt
26+
// CHECK: %[[TUPLE:[0-9]+]] = tuple (%[[OPT1]] : $Optional<Int>, %[[OPT2]] : $Optional<Int>)
27+
// CHECK: return %[[TUPLE]] : $(Optional<Int>, Optional<Int>)
28+
// CHECK: }
29+
30+
// The default value initializer for 'y' should have type Optional<Int>
31+
32+
//CHECK: sil [transparent] [ossa] @$s30implicit_property_initializers21HasDefaultTupleOfNilsV1ySiSgvpfi : $@convention(thin) () -> Optional<Int> {
33+
//CHECK: bb0:
34+
//CHECK: %[[OPT:[0-9]+]] = enum $Optional<Int>, #Optional.none!enumelt
35+
//CHECK: return %[[OPT]] : $Optional<Int>
36+
//CHECK: }
37+
38+
// There should not be a default value initializer for 'z'.
39+
40+
// CHECK-NOT: @$s30implicit_property_initializers21HasDefaultTupleOfNilsV1zSivpfi
41+
42+
// The default value initializer for 'w' should flatten to type (Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
43+
44+
//CHECK: sil [transparent] [ossa] @$[[W_VALUE_INIT:s30implicit_property_initializers21HasDefaultTupleOfNilsV1wSiSg_ytAEt_AE_AEttvpfi]] : $@convention(thin) () -> (Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>) {
45+
//CHECK: bb0:
46+
//CHECK: %[[OPT0:[0-9]+]] = enum $Optional<Int>, #Optional.none!enumelt
47+
//CHECK: %[[OPT1:[0-9]+]] = enum $Optional<Int>, #Optional.none!enumelt
48+
//CHECK: %[[OPT2:[0-9]+]] = enum $Optional<Int>, #Optional.none!enumelt
49+
//CHECK: %[[OPT3:[0-9]+]] = enum $Optional<Int>, #Optional.none!enumelt
50+
//CHECK: %[[TUPLE:[0-9]+]] = tuple (%[[OPT0]] : $Optional<Int>, %[[OPT1]] : $Optional<Int>, %[[OPT2]] : $Optional<Int>, %[[OPT3]] : $Optional<Int>)
51+
//CHECK: return %[[TUPLE]] : $(Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
52+
//CHECK: }
53+
54+
// The default arg generator for 'x' inside the memberwise init should have type (Optional<Int>, Optional<Int>)
55+
56+
// CHECK: sil [ossa] @$s30implicit_property_initializers21HasDefaultTupleOfNilsV1x1y1z1wACSiSg_AHt_AHSiAH_ytAHt_AH_AHtttcfcfA_ : $@convention(thin) () -> (Optional<Int>, Optional<Int>) {
57+
// CHECK: bb0:
58+
// CHECK: %[[INIT_FN:[0-9]+]] = function_ref @$[[X_VALUE_INIT]] : $@convention(thin) () -> (Optional<Int>, Optional<Int>)
59+
// CHECK: %[[RESULT:[0-9]+]] = apply %[[INIT_FN]]() : $@convention(thin) () -> (Optional<Int>, Optional<Int>)
60+
// CHECK: (%[[OPT1:[0-9]+]], %[[OPT2:[0-9]+]]) = destructure_tuple %[[RESULT]] : $(Optional<Int>, Optional<Int>)
61+
// CHECK: %[[TUPLE:[0-9]]] = tuple (%[[OPT1]] : $Optional<Int>, %[[OPT2]] : $Optional<Int>)
62+
// CHECK: return %[[TUPLE]] : $(Optional<Int>, Optional<Int>)
63+
// CHECK: }
64+
65+
// There should not be a default arg generator for 'y' because it's just a nil literal and clients construct it directly.
66+
67+
// CHECK-NOT: @$s30implicit_property_initializers21HasDefaultTupleOfNilsV1x1y1z1wACSiSg_AHt_AHSiAH_ytAHt_AH_AHtttcfcfA0_
68+
69+
// There should not be a default arg generator for 'z'
70+
71+
// CHECK-NOT: @$s30implicit_property_initializers21HasDefaultTupleOfNilsV1x1y1z1wACSiSg_AHt_AHSiAH_ytAHt_AH_AHtttcfcfA1_
72+
73+
// The default arg generator for 'w' should flatten to type (Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
74+
75+
// CHECK: sil [ossa] @$s30implicit_property_initializers21HasDefaultTupleOfNilsV1x1y1z1wACSiSg_AHt_AHSiAH_ytAHt_AH_AHtttcfcfA2_ : $@convention(thin) () -> (Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>) {
76+
// CHECK: bb0:
77+
// CHECK: %[[INIT_FN:[0-9]+]] = function_ref @$[[W_VALUE_INIT]] : $@convention(thin) () -> (Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
78+
// CHECK: %[[RESULT:[0-9]+]] = apply %[[INIT_FN:[0-9]+]]() : $@convention(thin) () -> (Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
79+
// CHECK: (%[[OPT1:[0-9]+]], %[[OPT2:[0-9]+]], %[[OPT3:[0-9]+]], %[[OPT4:[0-9]+]]) = destructure_tuple %[[RESULT]] : $(Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
80+
// CHECK: %[[TUPLE:[0-9]]] = tuple (%[[OPT1]] : $Optional<Int>, %[[OPT2]] : $Optional<Int>, %[[OPT3]] : $Optional<Int>, %[[OPT4]] : $Optional<Int>)
81+
// CHECK: return %[[TUPLE]] : $(Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
82+
// CHECK: }

0 commit comments

Comments
 (0)