Skip to content

Commit fa155bf

Browse files
committed
Sema: Rework typeCheckBinding() to use the new foundSolution() callback
Record the initializer type as soon as we have a solution, before it is applied, and get the type from the constriant system instead of from the final type checked expression. Note that the coerceToMaterializable() was unnecessary, since we always coerce the value to an rvalue type with coerceToType(). Eventually coerceToMaterializable() should go away. This is mostly NFC, except using the result of simplifyType() rather than the type of the final expression changes some diagnostics where it appears we were previously losing sugar. Also this accidentally fixes a crasher. Unfortunately the underlying issue is still there (applying a solution has bugs with opened existentials "leaking" out) -- this merely masks the problem by getting the initializer type directly from the constriant system.
1 parent f9d61a0 commit fa155bf

File tree

9 files changed

+58
-51
lines changed

9 files changed

+58
-51
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,20 +2131,21 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
21312131
class BindingListener : public ExprTypeCheckListener {
21322132
Pattern *&pattern;
21332133
Expr *&initializer;
2134-
DeclContext *DC;
21352134
bool skipClosures;
21362135

21372136
/// The locator we're using.
21382137
ConstraintLocator *Locator;
21392138

21402139
/// The type of the initializer.
21412140
Type InitType;
2142-
2141+
21432142
public:
21442143
explicit BindingListener(Pattern *&pattern, Expr *&initializer,
2145-
DeclContext *DC, bool skipClosures)
2146-
: pattern(pattern), initializer(initializer), DC(DC),
2147-
skipClosures(skipClosures) { }
2144+
bool skipClosures)
2145+
: pattern(pattern), initializer(initializer),
2146+
skipClosures(skipClosures), Locator(nullptr) { }
2147+
2148+
Type getInitType() const { return InitType; }
21482149

21492150
bool builtConstraints(ConstraintSystem &cs, Expr *expr) override {
21502151
// Save the locator we're using for the expression.
@@ -2164,12 +2165,15 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
21642165
return false;
21652166
}
21662167

2167-
Expr *appliedSolution(Solution &solution, Expr *expr) override {
2168+
Expr *foundSolution(Solution &solution, Expr *expr) override {
21682169
// Figure out what type the constraints decided on.
2169-
auto &cs = solution.getConstraintSystem();
2170-
auto &tc = cs.getTypeChecker();
21712170
InitType = solution.simplifyType(InitType);
21722171

2172+
// Just keep going.
2173+
return expr;
2174+
}
2175+
2176+
Expr *appliedSolution(Solution &solution, Expr *expr) override {
21732177
// Convert the initializer to the type of the pattern.
21742178
// ignoreTopLevelInjection = Binding->isConditional()
21752179
expr = solution.coerceToType(expr, InitType, Locator,
@@ -2179,29 +2183,15 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
21792183
return nullptr;
21802184
}
21812185

2182-
// Force the initializer to be materializable.
2183-
// FIXME: work this into the constraint system
2184-
expr = tc.coerceToMaterializable(expr);
2186+
assert(expr->getType()->isEqual(InitType));
21852187

2186-
// Apply the solution to the pattern as well.
2187-
Type patternType = expr->getType();
2188-
2189-
TypeResolutionOptions options;
2190-
options |= TR_OverrideType;
2191-
options |= TR_InExpression;
2192-
if (isa<EditorPlaceholderExpr>(expr->getSemanticsProvidingExpr())) {
2193-
options |= TR_EditorPlaceholder;
2194-
}
2195-
if (tc.coercePatternToType(pattern, DC, patternType, options)) {
2196-
return nullptr;
2197-
}
21982188
initializer = expr;
21992189
return expr;
22002190
}
22012191
};
22022192

22032193
assert(initializer && "type-checking an uninitialized binding?");
2204-
BindingListener listener(pattern, initializer, DC, skipClosures);
2194+
BindingListener listener(pattern, initializer, skipClosures);
22052195

22062196
TypeLoc contextualType;
22072197
auto contextualPurpose = CTP_Unused;
@@ -2230,11 +2220,27 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
22302220
contextualPurpose,
22312221
flags,
22322222
&listener);
2233-
2234-
if (hadError && !initializer->getType()) {
2235-
initializer->setType(ErrorType::get(Context));
2223+
2224+
if (!hadError) {
2225+
TypeResolutionOptions options;
2226+
options |= TR_OverrideType;
2227+
options |= TR_InExpression;
2228+
if (isa<EditorPlaceholderExpr>(initializer->getSemanticsProvidingExpr())) {
2229+
options |= TR_EditorPlaceholder;
2230+
}
2231+
2232+
// Apply the solution to the pattern as well.
2233+
if (coercePatternToType(pattern, DC, listener.getInitType(), options)) {
2234+
return true;
2235+
}
22362236
}
22372237

2238+
if (hadError && !initializer->getType())
2239+
initializer->setType(ErrorType::get(Context));
2240+
2241+
// If the type of the pattern is inferred, assign error types to the pattern
2242+
// and its variables, to prevent it from being referenced by the constraint
2243+
// system.
22382244
if (hadError &&
22392245
(!pattern->hasType() ||
22402246
pattern->getType()->hasUnboundGenericType())) {

test/Constraints/array_literal.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,15 @@ func defaultToAny(i: Int, s: String) {
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-
let _: Int = a2 // expected-error{{value of type '[Any]'}}
132+
let _: Int = a2 // expected-error{{value of type 'Array<Any>'}}
133133

134134
let a3 = [1, "a", nil, 3.5]
135135
// expected-error@-1{{heterogeneous collection literal could only be inferred to '[Any?]'; add explicit type annotation if this is intentional}}
136136
let _: Int = a3 // expected-error{{value of type '[Any?]'}}
137137

138138
let a4: Array = [1, "a", nil, 3.5]
139139
// 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?]'}}
140+
let _: Int = a4 // expected-error{{value of type 'Array<Any?>'}}
141141

142142
let a5 = []
143143
// expected-error@-1{{empty collection literal requires an explicit type}}

test/IDE/print_types.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ func testVariableTypes(_ param: Int, param2: inout Double) {
5757
_ = typealias1 ; typealias1 = 1
5858

5959
var optional1 = Optional<Int>.none
60-
// CHECK: VarDecl '''optional1''' Optional<Int>{{$}}
61-
// FULL: VarDecl '''optional1''' Swift.Optional<Swift.Int>{{$}}
60+
// CHECK: VarDecl '''optional1''' Int?{{$}}
61+
// FULL: VarDecl '''optional1''' Swift.Int?{{$}}
6262
_ = optional1 ; optional1 = nil
6363

6464
var optional2 = Optional<[Int]>.none
6565
_ = optional2 ; optional2 = nil
66-
// CHECK: VarDecl '''optional2''' Optional<[Int]>{{$}}
67-
// FULL: VarDecl '''optional2''' Swift.Optional<[Swift.Int]>{{$}}
66+
// CHECK: VarDecl '''optional2''' [Int]?{{$}}
67+
// FULL: VarDecl '''optional2''' [Swift.Int]?{{$}}
6868
}
6969

7070
func testFuncType1() {}

test/Interpreter/repl.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ for c in "foobar".unicodeScalars { print(c) }
148148
// CHECK-NEXT: r
149149

150150
var vec = Array<String>()
151-
// CHECK: vec : Array<String> = []
151+
// CHECK: vec : [String] = []
152152

153153
// Error recovery
154154
var a : [int]

test/expr/cast/dictionary_bridge.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@ func testUpcastBridge() {
8383
dictBO = dictBB as [BridgedToObjC: ObjC]
8484
dictOB = dictBB as [ObjC: BridgedToObjC]
8585

86-
dictBB = dictBO // expected-error{{cannot assign value of type 'Dictionary<BridgedToObjC, ObjC>' to type 'Dictionary<BridgedToObjC, BridgedToObjC>'}}
87-
dictBB = dictOB // expected-error{{cannot assign value of type 'Dictionary<ObjC, BridgedToObjC>' to type 'Dictionary<BridgedToObjC, BridgedToObjC>'}}
86+
dictBB = dictBO // expected-error{{cannot assign value of type '[BridgedToObjC : ObjC]' to type '[BridgedToObjC : BridgedToObjC]'}}
87+
dictBB = dictOB // expected-error{{cannot assign value of type '[ObjC : BridgedToObjC]' to type '[BridgedToObjC : BridgedToObjC]'}}
8888

89-
dictDO = dictBB // expected-error{{cannot assign value of type 'Dictionary<BridgedToObjC, BridgedToObjC>' to type 'Dictionary<DerivesObjC, ObjC>'}}
90-
dictOD = dictBB // expected-error{{cannot assign value of type 'Dictionary<BridgedToObjC, BridgedToObjC>' to type 'Dictionary<ObjC, DerivesObjC>'}}
91-
dictDD = dictBB // expected-error{{cannot assign value of type 'Dictionary<BridgedToObjC, BridgedToObjC>' to type 'Dictionary<DerivesObjC, DerivesObjC>'}}
89+
dictDO = dictBB // expected-error{{cannot assign value of type '[BridgedToObjC : BridgedToObjC]' to type '[DerivesObjC : ObjC]'}}
90+
dictOD = dictBB // expected-error{{cannot assign value of type '[BridgedToObjC : BridgedToObjC]' to type '[ObjC : DerivesObjC]'}}
91+
dictDD = dictBB // expected-error{{cannot assign value of type '[BridgedToObjC : BridgedToObjC]' to type '[DerivesObjC : DerivesObjC]'}}
9292

9393
_ = dictDD; _ = dictDO; _ = dictOD; _ = dictOO; _ = dictOR; _ = dictOR; _ = dictRR; _ = dictRO
9494
}
@@ -119,7 +119,7 @@ func testDowncastBridge() {
119119
_ = dictOB as Dictionary<BridgedToObjC, BridgedToObjC>
120120

121121
// We don't do mixed down/upcasts.
122-
_ = dictDO as! Dictionary<BridgedToObjC, BridgedToObjC> // expected-warning{{forced cast from 'Dictionary<DerivesObjC, ObjC>' to 'Dictionary<BridgedToObjC, BridgedToObjC>' always succeeds; did you mean to use 'as'?}}
122+
_ = dictDO as! Dictionary<BridgedToObjC, BridgedToObjC> // expected-warning{{forced cast from '[DerivesObjC : ObjC]' to 'Dictionary<BridgedToObjC, BridgedToObjC>' always succeeds; did you mean to use 'as'?}}
123123
}
124124

125125
func testConditionalDowncastBridge() {
@@ -149,7 +149,7 @@ func testConditionalDowncastBridge() {
149149

150150
// Mixed down/upcasts.
151151
if let d = dictDO as? Dictionary<BridgedToObjC, BridgedToObjC> { _ = d }
152-
// expected-warning@-1{{conditional cast from 'Dictionary<DerivesObjC, ObjC>' to 'Dictionary<BridgedToObjC, BridgedToObjC>' always succeeds}}
152+
// expected-warning@-1{{conditional cast from '[DerivesObjC : ObjC]' to 'Dictionary<BridgedToObjC, BridgedToObjC>' always succeeds}}
153153

154154
_ = dictRR
155155
_ = dictRO

test/expr/cast/dictionary_coerce.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ dictCC = dictDC
2424
dictCC = dictDD
2525

2626
dictCD = dictDD
27-
dictCD = dictCC // expected-error{{cannot assign value of type 'Dictionary<C, C>' to type 'Dictionary<C, D>'}}
27+
dictCD = dictCC // expected-error{{cannot assign value of type '[C : C]' to type '[C : D]'}}
2828

2929

3030
dictDC = dictDD
31-
dictDC = dictCD // expected-error{{cannot assign value of type 'Dictionary<C, D>' to type 'Dictionary<D, C>'}}
31+
dictDC = dictCD // expected-error{{cannot assign value of type '[C : D]' to type '[D : C]'}}
3232

33-
dictDD = dictCC // expected-error{{cannot assign value of type 'Dictionary<C, C>' to type 'Dictionary<D, D>'}}
33+
dictDD = dictCC // expected-error{{cannot assign value of type '[C : C]' to type '[D : D]'}}
3434

test/expr/cast/dictionary_downcast.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ if let _ = dictCC as? Dictionary<D, C> { }
3434
if let _ = dictCC as? Dictionary<D, D> { }
3535

3636
// Test dictionary downcasts to unrelated types.
37-
dictCC as Dictionary<D, U> // expected-error{{cannot convert value of type 'Dictionary<C, C>' to type 'Dictionary<D, U>' in coercion}}
38-
dictCC as Dictionary<U, D> // expected-error{{cannot convert value of type 'Dictionary<C, C>' to type 'Dictionary<U, D>' in coercion}}
39-
dictCC as Dictionary<U, U> // expected-error{{cannot convert value of type 'Dictionary<C, C>' to type 'Dictionary<U, U>' in coercion}}
37+
dictCC as Dictionary<D, U> // expected-error{{cannot convert value of type '[C : C]' to type 'Dictionary<D, U>' in coercion}}
38+
dictCC as Dictionary<U, D> // expected-error{{cannot convert value of type '[C : C]' to type 'Dictionary<U, D>' in coercion}}
39+
dictCC as Dictionary<U, U> // expected-error{{cannot convert value of type '[C : C]' to type 'Dictionary<U, U>' in coercion}}
4040

4141
// Test dictionary conditional downcasts to unrelated types
42-
if let _ = dictCC as? Dictionary<D, U> { } // expected-warning{{cast from 'Dictionary<C, C>' to unrelated type 'Dictionary<D, U>' always fails}}
43-
if let _ = dictCC as? Dictionary<U, D> { } // expected-warning{{cast from 'Dictionary<C, C>' to unrelated type 'Dictionary<U, D>' always fails}}
44-
if let _ = dictCC as? Dictionary<U, U> { } // expected-warning{{cast from 'Dictionary<C, C>' to unrelated type 'Dictionary<U, U>' always fails}}
42+
if let _ = dictCC as? Dictionary<D, U> { } // expected-warning{{cast from '[C : C]' to unrelated type 'Dictionary<D, U>' always fails}}
43+
if let _ = dictCC as? Dictionary<U, D> { } // expected-warning{{cast from '[C : C]' to unrelated type 'Dictionary<U, D>' always fails}}
44+
if let _ = dictCC as? Dictionary<U, U> { } // expected-warning{{cast from '[C : C]' to unrelated type 'Dictionary<U, U>' always fails}}
4545

test/stmt/statements.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ func testThrowNil() throws {
418418
// condition may have contained a SequenceExpr.
419419
func r23684220(_ b: Any) {
420420
if let _ = b ?? b {} // expected-error {{initializer for conditional binding must have Optional type, not 'Any'}}
421+
// expected-warning@-1 {{left side of nil coalescing operator '??' has non-optional type 'Any', so the right side is never used}}
421422
}
422423

423424

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
// See https://swift.org/LICENSE.txt for license information
66
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// RUN: not --crash %target-swift-frontend %s -emit-ir
8+
// RUN: not %target-swift-frontend %s -emit-ir
99
protocol A:RangeReplaceableCollection
1010
guard let c=A.init(

0 commit comments

Comments
 (0)