Skip to content

[CSGen] Don't increase optionality of weak var patterns #39162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2189,38 +2189,54 @@ namespace {
}
}

if (!varType)
if (!varType) {
varType = CS.createTypeVariable(CS.getConstraintLocator(locator),
TVO_CanBindToNoEscape);

// If this is either a `weak` declaration or capture e.g.
// `weak var ...` or `[weak self]`. Let's wrap type variable
// into an optional.
if (optionality == ReferenceOwnershipOptionality::Required)
varType = TypeChecker::getOptionalType(var->getLoc(), varType);
}

// When we are supposed to bind pattern variables, create a fresh
// type variable and a one-way constraint to assign it to either the
// deduced type or the externally-imposed type.
Type oneWayVarType;
if (bindPatternVarsOneWay) {
oneWayVarType = CS.createTypeVariable(
CS.getConstraintLocator(locator), TVO_CanBindToNoEscape);
CS.addConstraint(
ConstraintKind::OneWayEqual, oneWayVarType,
externalPatternType ? externalPatternType : varType, locator);
}

// If there is an externally-imposed type.

switch (optionality) {
case ReferenceOwnershipOptionality::Required:
varType = TypeChecker::getOptionalType(var->getLoc(), varType);
assert(!varType->hasError());
// If there is an externally-imposed pattern type and the
// binding/capture is marked as `weak`, let's make sure
// that the imposed type is optional.
//
// Note that there is no need to check `varType` since
// it's only "externally" bound if this pattern isn't marked
// as `weak`.
if (externalPatternType &&
optionality == ReferenceOwnershipOptionality::Required) {
// If the type is not yet known, let's add a constraint
// to make sure that it can only be bound to an optional type.
if (externalPatternType->isTypeVariableOrMember()) {
auto objectTy = CS.createTypeVariable(
CS.getConstraintLocator(locator.withPathElement(
ConstraintLocator::OptionalPayload)),
TVO_CanBindToLValue | TVO_CanBindToNoEscape);

if (oneWayVarType) {
oneWayVarType =
TypeChecker::getOptionalType(var->getLoc(), oneWayVarType);
CS.addConstraint(ConstraintKind::OptionalObject,
externalPatternType, objectTy, locator);
} else if (!externalPatternType->getOptionalObjectType()) {
// TODO(diagnostics): A tailored fix to indiciate that `weak`
// should have an optional type.
return Type();
}
}
break;

case ReferenceOwnershipOptionality::Allowed:
case ReferenceOwnershipOptionality::Disallowed:
break;
CS.addConstraint(ConstraintKind::OneWayEqual, oneWayVarType,
externalPatternType ? externalPatternType : varType,
locator);
}

// If we have a type to ascribe to the variable, do so now.
Expand Down
16 changes: 16 additions & 0 deletions test/Constraints/result_builder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -788,3 +788,19 @@ let ts1 = MyTupleStruct {

// CHECK: MyTupleStruct<(Int, String, Optional<String>), (Double, String)>(first: (Function), second: (3.14159, "blah"))
print(ts1)

// Make sure that `weakV` is `Test?` and not `Test??`
func test_weak_optionality_stays_the_same() {
class Test {
func fn() -> Int { 42 }
}

tuplify(true) { c in
weak var weakV: Test? = Test()

0
if let v = weakV {
v.fn()
}
}
}