Skip to content

Commit fb5ac6d

Browse files
committed
[Constraint solver] Fix an issue with rewriting OpenExistentialExpr.
If we fail when doing a coercion while generating an OpenExistentialExpr when applying a solution during type checking, make sure that the opaque value on that OpenExistentialExpr is cleared. We do not visit these during normal AST walks because they normally appear in the subexpression held by the OpenExistentialExpr. In this case, however, we replace that subexpression with an ErrorExpr which means we will not visit the opaque value at all, so certain operations, like setting the type on the opaque value, will never happen, and we can run into problems later by code that assumes the type is set. It seems reasonable to just clear these out in cases like this since they are not reachable by any normal means.
1 parent 55843a2 commit fb5ac6d

File tree

3 files changed

+33
-11
lines changed

3 files changed

+33
-11
lines changed

lib/AST/ASTVerifier.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,11 @@ class Verifier : public ASTWalker {
697697
if (!shouldVerify(cast<Expr>(expr)))
698698
return false;
699699

700+
// In rare instances we clear the opaque value because we no
701+
// longer have a subexpression that references it.
702+
if (!expr->getOpaqueValue())
703+
return true;
704+
700705
assert(!OpaqueValues.count(expr->getOpaqueValue()));
701706
OpaqueValues[expr->getOpaqueValue()] = 0;
702707
assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==0);
@@ -705,6 +710,11 @@ class Verifier : public ASTWalker {
705710
}
706711

707712
void cleanup(OpenExistentialExpr *expr) {
713+
// In rare instances we clear the opaque value because we no
714+
// longer have a subexpression that references it.
715+
if (!expr->getOpaqueValue())
716+
return;
717+
708718
assert(OpaqueValues.count(expr->getOpaqueValue()));
709719
OpaqueValues.erase(expr->getOpaqueValue());
710720
assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==1);

lib/AST/Expr.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -316,19 +316,25 @@ void Expr::propagateLValueAccessKind(AccessKind accessKind,
316316

317317
void visitOpenExistentialExpr(OpenExistentialExpr *E,
318318
AccessKind accessKind) {
319-
bool opaqueValueHadAK = E->getOpaqueValue()->hasLValueAccessKind();
320-
AccessKind oldOpaqueValueAK =
321-
(opaqueValueHadAK ? E->getOpaqueValue()->getLValueAccessKind()
322-
: AccessKind::Read);
319+
AccessKind oldOpaqueValueAK;
320+
bool opaqueValueHadAK;
321+
if (E->getOpaqueValue()) {
322+
opaqueValueHadAK = E->getOpaqueValue()->hasLValueAccessKind();
323+
oldOpaqueValueAK =
324+
(opaqueValueHadAK ? E->getOpaqueValue()->getLValueAccessKind()
325+
: AccessKind::Read);
326+
}
323327

324328
visit(E->getSubExpr(), accessKind);
325329

326-
// Propagate the new access kind from the OVE to the original existential
327-
// if we just set or changed it on the OVE.
328-
if (E->getOpaqueValue()->hasLValueAccessKind()) {
329-
auto newOpaqueValueAK = E->getOpaqueValue()->getLValueAccessKind();
330-
if (!opaqueValueHadAK || newOpaqueValueAK != oldOpaqueValueAK)
331-
visit(E->getExistentialValue(), newOpaqueValueAK);
330+
if (E->getOpaqueValue()) {
331+
// Propagate the new access kind from the OVE to the original
332+
// existential if we just set or changed it on the OVE.
333+
if (E->getOpaqueValue()->hasLValueAccessKind()) {
334+
auto newOpaqueValueAK = E->getOpaqueValue()->getLValueAccessKind();
335+
if (!opaqueValueHadAK || newOpaqueValueAK != oldOpaqueValueAK)
336+
visit(E->getExistentialValue(), newOpaqueValueAK);
337+
}
332338
}
333339
}
334340

lib/Sema/CSApply.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,12 @@ namespace {
760760
if (result == nullptr) {
761761
result = new (tc.Context) ErrorExpr(range);
762762
cs.setType(result, erasedTy);
763+
// The opaque value is no longer reachable in an AST walk as
764+
// a result of the result above being replaced with an
765+
// ErrorExpr, but there is code expecting to have a type set
766+
// on it. Since we no longer have a reachable reference,
767+
// we'll null this out.
768+
record.OpaqueValue = nullptr;
763769
}
764770
}
765771

@@ -768,7 +774,7 @@ namespace {
768774
// means this is our only chance to propagate the l-value access kind
769775
// down to the original existential value. Otherwise, propagateLVAK
770776
// will handle this.
771-
if (record.OpaqueValue->hasLValueAccessKind())
777+
if (record.OpaqueValue && record.OpaqueValue->hasLValueAccessKind())
772778
cs.propagateLValueAccessKind(record.ExistentialValue,
773779
record.OpaqueValue->getLValueAccessKind());
774780

0 commit comments

Comments
 (0)