Skip to content

Commit 4277f11

Browse files
author
Harlan Haskins
authored
Merge pull request swiftlang#26506 from harlanhaskins/extremely-default-and-incredibly-nil
[AST] Handle printing default values for tuples of nils
2 parents 206994c + 7fd8649 commit 4277f11

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
@@ -5944,6 +5944,46 @@ Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var,
59445944
return initArg;
59455945
}
59465946

5947+
/// Writes a tuple expression where each element is either `nil` or another such
5948+
/// tuple of nils.
5949+
/// This comes up when printing default arguments for memberwise initializers
5950+
/// that were created implicitly.
5951+
/// For example, this var:
5952+
/// ```
5953+
/// var x: (Int?, (Int?, Int?, ()))
5954+
/// ```
5955+
/// will produce `(nil, (nil, nil, ()))`
5956+
static void writeTupleOfNils(TupleType *type, llvm::raw_ostream &os) {
5957+
os << '(';
5958+
for (unsigned i = 0; i < type->getNumElements(); ++i) {
5959+
auto &elt = type->getElement(i);
5960+
if (elt.hasName()) {
5961+
os << elt.getName().str() << ": ";
5962+
}
5963+
5964+
if (elt.getType()->getOptionalObjectType()) {
5965+
os << "nil";
5966+
} else {
5967+
writeTupleOfNils(elt.getType()->castTo<TupleType>(), os);
5968+
}
5969+
if (i < type->getNumElements() - 1) {
5970+
os << ", ";
5971+
}
5972+
}
5973+
os << ')';
5974+
}
5975+
5976+
/// Determines if the given type is a potentially nested tuple of optional
5977+
/// types.
5978+
static bool isTupleOfOptionals(Type type) {
5979+
auto tuple = type->getAs<TupleType>();
5980+
if (!tuple) return false;
5981+
for (auto elt : tuple->getElementTypes())
5982+
if (!elt->getOptionalObjectType() && !isTupleOfOptionals(elt))
5983+
return false;
5984+
return true;
5985+
}
5986+
59475987
StringRef
59485988
ParamDecl::getDefaultValueStringRepresentation(
59495989
SmallVectorImpl<char> &scratch) const {
@@ -6010,8 +6050,24 @@ ParamDecl::getDefaultValueStringRepresentation(
60106050
}
60116051
}
60126052

6053+
auto init = var->getParentInitializer();
6054+
if (!init || !init->getSourceRange().isValid()) {
6055+
// Special case: There are two possible times where we will synthesize a
6056+
// default initial value for a stored property: if the type
6057+
// is Optional, or if it's a (potentially nested) tuple of
6058+
// all Optional elements. If it's Optional, we'll set
6059+
// the DefaultArgumentKind to NilLiteral, but if we're still
6060+
// handling a StoredProperty, then we know it's a tuple.
6061+
if (isTupleOfOptionals(getInterfaceType())) {
6062+
llvm::raw_svector_ostream os(scratch);
6063+
writeTupleOfNils(getInterfaceType()->castTo<TupleType>(), os);
6064+
return os.str();
6065+
}
6066+
return "<<empty>>";
6067+
}
6068+
60136069
return extractInlinableText(getASTContext().SourceMgr,
6014-
var->getParentInitializer(),
6070+
init,
60156071
scratch);
60166072
}
60176073
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: %0 = enum $Optional<Int>, #Optional.none!enumelt
25+
// CHECK: %1 = enum $Optional<Int>, #Optional.none!enumelt
26+
// CHECK: %2 = tuple (%0 : $Optional<Int>, %1 : $Optional<Int>)
27+
// CHECK: return %2 : $(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: %0 = enum $Optional<Int>, #Optional.none!enumelt // user: %1
35+
//CHECK: return %0 : $Optional<Int> // id: %1
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: %0 = enum $Optional<Int>, #Optional.none!enumelt // user: %4
47+
//CHECK: %1 = enum $Optional<Int>, #Optional.none!enumelt // user: %4
48+
//CHECK: %2 = enum $Optional<Int>, #Optional.none!enumelt // user: %4
49+
//CHECK: %3 = enum $Optional<Int>, #Optional.none!enumelt // user: %4
50+
//CHECK: %4 = tuple (%0 : $Optional<Int>, %1 : $Optional<Int>, %2 : $Optional<Int>, %3 : $Optional<Int>) // user: %5
51+
//CHECK: return %4 : $(Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>) // id: %5
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: %0 = function_ref @$[[X_VALUE_INIT]] : $@convention(thin) () -> (Optional<Int>, Optional<Int>) // user: %1
59+
// CHECK: %1 = apply %0() : $@convention(thin) () -> (Optional<Int>, Optional<Int>)
60+
// CHECK: (%2, %3) = destructure_tuple %1 : $(Optional<Int>, Optional<Int>)
61+
// CHECK: %4 = tuple (%2 : $Optional<Int>, %3 : $Optional<Int>)
62+
// CHECK: return %4 : $(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: %0 = function_ref @$[[W_VALUE_INIT]] : $@convention(thin) () -> (Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
78+
// CHECK: %1 = apply %0() : $@convention(thin) () -> (Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
79+
// CHECK: (%2, %3, %4, %5) = destructure_tuple %1 : $(Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
80+
// CHECK: %6 = tuple (%2 : $Optional<Int>, %3 : $Optional<Int>, %4 : $Optional<Int>, %5 : $Optional<Int>)
81+
// CHECK: return %6 : $(Optional<Int>, Optional<Int>, Optional<Int>, Optional<Int>)
82+
// CHECK: }

0 commit comments

Comments
 (0)