Skip to content

Commit 3bbde55

Browse files
committed
[ConstraintSystem] Detect and diagnose incorrectly typed weak declarations
All `weak` declarations are supposed to have an optional type. Detect situations when is not an optional, wrap it as a fix, and diagnose the problem.
1 parent 60d9316 commit 3bbde55

File tree

4 files changed

+60
-27
lines changed

4 files changed

+60
-27
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7784,7 +7784,7 @@ bool InvalidWeakAttributeUse::diagnoseAsError() {
77847784
return false;
77857785

77867786
auto *var = pattern->getDecl();
7787-
auto varType = getType(var);
7787+
auto varType = OptionalType::get(getType(var));
77887788

77897789
auto diagnostic =
77907790
emitDiagnosticAt(var, diag::invalid_ownership_not_optional,

lib/Sema/CSGen.cpp

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2210,31 +2210,19 @@ namespace {
22102210
oneWayVarType = CS.createTypeVariable(
22112211
CS.getConstraintLocator(locator), TVO_CanBindToNoEscape);
22122212

2213-
// If there is an externally-imposed pattern type and the
2214-
// binding/capture is marked as `weak`, let's make sure
2215-
// that the imposed type is optional.
2213+
// If there is externally-imposed type, and the variable
2214+
// is marked as `weak`, let's fallthrough and allow the
2215+
// `one-way` constraint to be fixed in diagnostic mode.
22162216
//
2217-
// Note that there is no need to check `varType` since
2218-
// it's only "externally" bound if this pattern isn't marked
2219-
// as `weak`.
2220-
if (externalPatternType &&
2221-
optionality == ReferenceOwnershipOptionality::Required) {
2222-
// If the type is not yet known, let's add a constraint
2223-
// to make sure that it can only be bound to an optional type.
2224-
if (externalPatternType->isTypeVariableOrMember()) {
2225-
auto objectTy = CS.createTypeVariable(
2226-
CS.getConstraintLocator(locator.withPathElement(
2227-
ConstraintLocator::OptionalPayload)),
2228-
TVO_CanBindToLValue | TVO_CanBindToNoEscape);
2229-
2230-
CS.addConstraint(ConstraintKind::OptionalObject,
2231-
externalPatternType, objectTy, locator);
2232-
} else if (!externalPatternType->getOptionalObjectType()) {
2233-
// TODO(diagnostics): A tailored fix to indiciate that `weak`
2234-
// should have an optional type.
2235-
return Type();
2236-
}
2237-
}
2217+
// That would make sure that type of this variable is
2218+
// recorded in the constraint system, which would then
2219+
// be used instead of `getVarType` upon discovering a
2220+
// reference to this variable in subsequent expression(s).
2221+
//
2222+
// If we let constraint generation fail here, it would trigger
2223+
// interface type request via `var->getType()` that would
2224+
// attempt to validate `weak` attribute, and produce a
2225+
// diagnostic in the middle of the solver path.
22382226

22392227
CS.addConstraint(ConstraintKind::OneWayEqual, oneWayVarType,
22402228
externalPatternType ? externalPatternType : varType,

lib/Sema/CSSimplify.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4956,6 +4956,25 @@ bool ConstraintSystem::repairFailures(
49564956
*this, lhs, rhs, getConstraintLocator(locator)));
49574957
}
49584958

4959+
// `weak` declaration with an explicit non-optional type e.g.
4960+
// `weak x: X = ...` where `X` is a class.
4961+
if (auto *TP = dyn_cast<TypedPattern>(pattern)) {
4962+
if (auto *NP = dyn_cast<NamedPattern>(TP->getSubPattern())) {
4963+
auto *var = NP->getDecl();
4964+
4965+
auto ROK = ReferenceOwnership::Strong;
4966+
if (auto *OA = var->getAttrs().getAttribute<ReferenceOwnershipAttr>())
4967+
ROK = OA->get();
4968+
4969+
if (!rhs->getOptionalObjectType() &&
4970+
optionalityOf(ROK) == ReferenceOwnershipOptionality::Required) {
4971+
conversionsOrFixes.push_back(
4972+
AllowNonOptionalWeak::create(*this, getConstraintLocator(NP)));
4973+
break;
4974+
}
4975+
}
4976+
}
4977+
49594978
break;
49604979
}
49614980

@@ -11544,8 +11563,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1154411563
case FixKind::AllowInvalidStaticMemberRefOnProtocolMetatype:
1154511564
case FixKind::AllowWrappedValueMismatch:
1154611565
case FixKind::RemoveExtraneousArguments:
11547-
case FixKind::SpecifyTypeForPlaceholder:
11548-
case FixKind::AllowNonOptionalWeak: {
11566+
case FixKind::SpecifyTypeForPlaceholder: {
1154911567
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
1155011568
}
1155111569

@@ -11710,6 +11728,17 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1171011728
return SolutionKind::Solved;
1171111729
}
1171211730

11731+
case FixKind::AllowNonOptionalWeak: {
11732+
if (recordFix(fix))
11733+
return SolutionKind::Error;
11734+
11735+
(void)matchTypes(type1, OptionalType::get(type2),
11736+
ConstraintKind::Conversion,
11737+
TypeMatchFlags::TMF_ApplyingFix, locator);
11738+
11739+
return SolutionKind::Solved;
11740+
}
11741+
1171311742
case FixKind::UseSubscriptOperator:
1171411743
case FixKind::ExplicitlyEscaping:
1171511744
case FixKind::MarkGlobalActorFunction:

test/Constraints/result_builder_diags.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,3 +781,19 @@ func test_rdar65667992() {
781781
}
782782
}
783783
}
784+
785+
func test_weak_with_nonoptional_type() {
786+
class X {
787+
func test() -> Int { 0 }
788+
}
789+
790+
tuplify(true) { c in
791+
weak var x: X = X() // expected-error {{'weak' variable should have optional type 'X?'}}
792+
793+
if let x = x {
794+
x.test()
795+
}
796+
797+
42
798+
}
799+
}

0 commit comments

Comments
 (0)