Skip to content

Commit 96b01c4

Browse files
authored
Merge pull request #8339 from tonisuter/SR-4347
[Sema] [SR-4347] Improve inference of optional supertypes
2 parents 4f52f84 + 09a56c1 commit 96b01c4

File tree

4 files changed

+168
-25
lines changed

4 files changed

+168
-25
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,22 +1173,30 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
11731173
// If we're supposed to add optional supertype bindings, do so now.
11741174
if (addOptionalSupertypeBindings) {
11751175
for (unsigned i : indices(result.Bindings)) {
1176-
// Only interested in supertype bindings.
11771176
auto &binding = result.Bindings[i];
1178-
if (binding.Kind != AllowedBindingKind::Supertypes) continue;
1179-
1180-
// If the type doesn't conform to ExpressibleByNilLiteral,
1181-
// produce an optional of that type as a potential binding. We
1182-
// overwrite the binding in place because the non-optional type
1183-
// will fail to type-check against the nil-literal conformance.
1184-
auto nominalBindingDecl = binding.BindingType->getAnyNominal();
1185-
if (!nominalBindingDecl) continue;
1186-
SmallVector<ProtocolConformance *, 2> conformances;
1187-
if (!nominalBindingDecl->lookupConformance(
1188-
cs.DC->getParentModule(),
1189-
cs.getASTContext().getProtocol(
1190-
KnownProtocolKind::ExpressibleByNilLiteral),
1191-
conformances)) {
1177+
bool wrapInOptional = false;
1178+
1179+
if (binding.Kind == AllowedBindingKind::Supertypes) {
1180+
// If the type doesn't conform to ExpressibleByNilLiteral,
1181+
// produce an optional of that type as a potential binding. We
1182+
// overwrite the binding in place because the non-optional type
1183+
// will fail to type-check against the nil-literal conformance.
1184+
auto nominalBindingDecl = binding.BindingType->getAnyNominal();
1185+
bool conformsToExprByNilLiteral = false;
1186+
if (nominalBindingDecl) {
1187+
SmallVector<ProtocolConformance *, 2> conformances;
1188+
conformsToExprByNilLiteral = nominalBindingDecl->lookupConformance(
1189+
cs.DC->getParentModule(),
1190+
cs.getASTContext().getProtocol(
1191+
KnownProtocolKind::ExpressibleByNilLiteral),
1192+
conformances);
1193+
}
1194+
wrapInOptional = !conformsToExprByNilLiteral;
1195+
} else if (binding.isDefaultableBinding() && binding.BindingType->isAny()) {
1196+
wrapInOptional = true;
1197+
}
1198+
1199+
if (wrapInOptional) {
11921200
binding.BindingType = OptionalType::get(binding.BindingType);
11931201
}
11941202
}

test/Constraints/array_literal.swift

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -121,32 +121,47 @@ class A { }
121121
class B : A { }
122122
class C : A { }
123123

124-
/// Check for defaulting the element type to 'Any'.
124+
/// Check for defaulting the element type to 'Any' / 'Any?'.
125125
func defaultToAny(i: Int, s: String) {
126126
let a1 = [1, "a", 3.5]
127127
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
128128
let _: Int = a1 // expected-error{{value of type '[Any]'}}
129129

130130
let a2: Array = [1, "a", 3.5]
131131
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional}}
132-
133132
let _: Int = a2 // expected-error{{value of type '[Any]'}}
134-
135-
let a3 = []
133+
134+
let a3 = [1, "a", nil, 3.5]
135+
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
136+
let _: Int = a3 // expected-error{{value of type '[Any?]'}}
137+
138+
let a4: Array = [1, "a", nil, 3.5]
139+
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
140+
let _: Int = a4 // expected-error{{value of type '[Any?]'}}
141+
142+
let a5 = []
136143
// expected-error@-1{{empty collection literal requires an explicit type}}
137-
138-
let _: Int = a3 // expected-error{{value of type '[Any]'}}
144+
let _: Int = a5 // expected-error{{value of type '[Any]'}}
139145

140146
let _: [Any] = [1, "a", 3.5]
141147
let _: [Any] = [1, "a", [3.5, 3.7, 3.9]]
142148
let _: [Any] = [1, "a", [3.5, "b", 3]]
149+
150+
let _: [Any?] = [1, "a", nil, 3.5]
151+
let _: [Any?] = [1, "a", nil, [3.5, 3.7, 3.9]]
152+
let _: [Any?] = [1, "a", nil, [3.5, "b", nil]]
143153

144-
let a4 = [B(), C()]
145-
let _: Int = a4 // expected-error{{value of type '[A]'}}
154+
let a6 = [B(), C()]
155+
let _: Int = a6 // expected-error{{value of type '[A]'}}
146156
}
147157

148158
/// Check handling of 'nil'.
149-
func joinWithNil(s: String) {
159+
protocol Proto1 {}
160+
protocol Proto2 {}
161+
struct Nilable: ExpressibleByNilLiteral {
162+
init(nilLiteral: ()) {}
163+
}
164+
func joinWithNil<T>(s: String, a: Any, t: T, m: T.Type, p: Proto1 & Proto2, arr: [Int], opt: Int?, iou: Int!, n: Nilable) {
150165
let a1 = [s, nil]
151166
let _: Int = a1 // expected-error{{value of type '[String?]'}}
152167

@@ -158,6 +173,72 @@ func joinWithNil(s: String) {
158173

159174
let a4 = [nil, "hello"]
160175
let _: Int = a4 // expected-error{{value of type '[String?]'}}
176+
177+
let a5 = [(s, s), nil]
178+
let _: Int = a5 // expected-error{{value of type '[(String, String)?]'}}
179+
180+
let a6 = [nil, (s, s)]
181+
let _: Int = a6 // expected-error{{value of type '[(String, String)?]'}}
182+
183+
let a7 = [("hello", "world"), nil]
184+
let _: Int = a7 // expected-error{{value of type '[(String, String)?]'}}
185+
186+
let a8 = [nil, ("hello", "world")]
187+
let _: Int = a8 // expected-error{{value of type '[(String, String)?]'}}
188+
189+
let a9 = [{ $0 * 2 }, nil]
190+
let _: Int = a9 // expected-error{{value of type '[((Int) -> Int)?]'}}
191+
192+
let a10 = [nil, { $0 * 2 }]
193+
let _: Int = a10 // expected-error{{value of type '[((Int) -> Int)?]'}}
194+
195+
let a11 = [a, nil]
196+
let _: Int = a11 // expected-error{{value of type '[Any?]'}}
197+
198+
let a12 = [nil, a]
199+
let _: Int = a12 // expected-error{{value of type '[Any?]'}}
200+
201+
let a13 = [t, nil]
202+
let _: Int = a13 // expected-error{{value of type '[T?]'}}
203+
204+
let a14 = [nil, t]
205+
let _: Int = a14 // expected-error{{value of type '[T?]'}}
206+
207+
let a15 = [m, nil]
208+
let _: Int = a15 // expected-error{{value of type '[T.Type?]'}}
209+
210+
let a16 = [nil, m]
211+
let _: Int = a16 // expected-error{{value of type '[T.Type?]'}}
212+
213+
let a17 = [p, nil]
214+
let _: Int = a17 // expected-error{{value of type '[(Proto1 & Proto2)?]'}}
215+
216+
let a18 = [nil, p]
217+
let _: Int = a18 // expected-error{{value of type '[(Proto1 & Proto2)?]'}}
218+
219+
let a19 = [arr, nil]
220+
let _: Int = a19 // expected-error{{value of type '[[Int]?]'}}
221+
222+
let a20 = [nil, arr]
223+
let _: Int = a20 // expected-error{{value of type '[[Int]?]'}}
224+
225+
let a21 = [opt, nil]
226+
let _: Int = a21 // expected-error{{value of type '[Int?]'}}
227+
228+
let a22 = [nil, opt]
229+
let _: Int = a22 // expected-error{{value of type '[Int?]'}}
230+
231+
let a23 = [iou, nil]
232+
let _: Int = a23 // expected-error{{value of type '[Int?]'}}
233+
234+
let a24 = [nil, iou]
235+
let _: Int = a24 // expected-error{{value of type '[Int?]'}}
236+
237+
let a25 = [n, nil]
238+
let _: Int = a25 // expected-error{{value of type '[Nilable]'}}
239+
240+
let a26 = [nil, n]
241+
let _: Int = a26 // expected-error{{value of type '[Nilable]'}}
161242
}
162243

163244
struct OptionSetLike : ExpressibleByArrayLiteral {

test/Constraints/dictionary_literal.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ func testDefaultExistentials() {
7272
// expected-error@-1{{heterogeneous collection literal could only be inferred to 'Dictionary<String, Any>'; add explicit type annotation if this is intentional}}{{46-46= as Dictionary<String, Any>}}
7373

7474
let _: [String : Any] = ["a" : 1, "b" : 2.5, "c" : "hello"]
75+
76+
let _ = ["a" : 1, "b" : nil, "c" : "hello"]
77+
// expected-error@-1{{heterogeneous collection literal could only be inferred to 'Dictionary<String, Any?>' (aka 'Dictionary<String, Optional<Any>>'); add explicit type annotation if this is intentional}}{{46-46= as Dictionary<String, Any?>}}
78+
79+
let _: [String : Any?] = ["a" : 1, "b" : nil, "c" : "hello"]
7580

7681
let d2 = [:]
7782
// expected-error@-1{{empty collection literal requires an explicit type}}

test/Constraints/optional.swift

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,12 @@ func testVoidOptional() {
120120
voidOptional(optNoop)
121121
}
122122

123-
func testTernaryWithNil(b: Bool, s: String, i: Int) {
123+
protocol Proto1 {}
124+
protocol Proto2 {}
125+
struct Nilable: ExpressibleByNilLiteral {
126+
init(nilLiteral: ()) {}
127+
}
128+
func testTernaryWithNil<T>(b: Bool, s: String, i: Int, a: Any, t: T, m: T.Type, p: Proto1 & Proto2, arr: [Int], opt: Int?, iou: Int!, n: Nilable) {
124129
let t1 = b ? s : nil
125130
let _: Double = t1 // expected-error{{value of type 'String?'}}
126131
let t2 = b ? nil : i
@@ -129,6 +134,50 @@ func testTernaryWithNil(b: Bool, s: String, i: Int) {
129134
let _: Double = t3 // expected-error{{value of type 'String?'}}
130135
let t4 = b ? nil : 1
131136
let _: Double = t4 // expected-error{{value of type 'Int?'}}
137+
let t5 = b ? (s, i) : nil
138+
let _: Double = t5 // expected-error{{value of type '(String, Int)?}}
139+
let t6 = b ? nil : (i, s)
140+
let _: Double = t6 // expected-error{{value of type '(Int, String)?}}
141+
let t7 = b ? ("hello", 1) : nil
142+
let _: Double = t7 // expected-error{{value of type '(String, Int)?}}
143+
let t8 = b ? nil : (1, "hello")
144+
let _: Double = t8 // expected-error{{value of type '(Int, String)?}}
145+
let t9 = b ? { $0 * 2 } : nil
146+
let _: Double = t9 // expected-error{{value of type '((Int) -> Int)?}}
147+
let t10 = b ? nil : { $0 * 2 }
148+
let _: Double = t10 // expected-error{{value of type '((Int) -> Int)?}}
149+
let t11 = b ? a : nil
150+
let _: Double = t11 // expected-error{{value of type 'Any?'}}
151+
let t12 = b ? nil : a
152+
let _: Double = t12 // expected-error{{value of type 'Any?'}}
153+
let t13 = b ? t : nil
154+
let _: Double = t13 // expected-error{{value of type 'T?'}}
155+
let t14 = b ? nil : t
156+
let _: Double = t14 // expected-error{{value of type 'T?'}}
157+
let t15 = b ? m : nil
158+
let _: Double = t15 // expected-error{{value of type 'T.Type?'}}
159+
let t16 = b ? nil : m
160+
let _: Double = t16 // expected-error{{value of type 'T.Type?'}}
161+
let t17 = b ? p : nil
162+
let _: Double = t17 // expected-error{{value of type '(Proto1 & Proto2)?'}}
163+
let t18 = b ? nil : p
164+
let _: Double = t18 // expected-error{{value of type '(Proto1 & Proto2)?'}}
165+
let t19 = b ? arr : nil
166+
let _: Double = t19 // expected-error{{value of type '[Int]?'}}
167+
let t20 = b ? nil : arr
168+
let _: Double = t20 // expected-error{{value of type '[Int]?'}}
169+
let t21 = b ? opt : nil
170+
let _: Double = t21 // expected-error{{value of type 'Int?'}}
171+
let t22 = b ? nil : opt
172+
let _: Double = t22 // expected-error{{value of type 'Int?'}}
173+
let t23 = b ? iou : nil
174+
let _: Double = t23 // expected-error{{value of type 'Int?'}}
175+
let t24 = b ? nil : iou
176+
let _: Double = t24 // expected-error{{value of type 'Int?'}}
177+
let t25 = b ? n : nil
178+
let _: Double = t25 // expected-error{{value of type 'Nilable'}}
179+
let t26 = b ? nil : n
180+
let _: Double = t26 // expected-error{{value of type 'Nilable'}}
132181
}
133182

134183
// inference with IUOs

0 commit comments

Comments
 (0)