mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Make the rvalue-as-lvalue fix symmetric for bind constraints, which causes another set of assignment errors to be discovered in
the CS and slightly reduces the code in CSDiag.
This commit is contained in:
@@ -4420,12 +4420,6 @@ bool FailureDiagnosis::diagnoseSubscriptErrors(SubscriptExpr *SE,
|
||||
if (calleeInfo.diagnoseSimpleErrors(SE))
|
||||
return true;
|
||||
|
||||
// If we haven't found a diagnostic yet, and we are in an assignment's
|
||||
// destination, continue with diagnosing the assignment rather than giving
|
||||
// a last resort diagnostic here.
|
||||
if (inAssignmentDestination)
|
||||
return false;
|
||||
|
||||
diagnose(SE->getLoc(), diag::cannot_subscript_with_index, baseType,
|
||||
indexType);
|
||||
|
||||
@@ -5826,11 +5820,17 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) {
|
||||
if (diagnoseSubscriptErrors(subscriptExpr, /* inAssignmentDestination = */ true))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Member ref assignment errors detected elsewhere, so not an assignment issue if found here.
|
||||
// The remaining exception involves mutable pointer conversions which aren't always caught elsewhere.
|
||||
PointerTypeKind ptk;
|
||||
if (!isa<MemberRefExpr>(destExpr) || CS.getType(destExpr)
|
||||
->lookThroughAllOptionalTypes()
|
||||
->getAnyPointerElementType(ptk)) {
|
||||
AssignmentFailure failure(destExpr, CS, assignExpr->getLoc());
|
||||
if (failure.diagnoseAsError())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
auto *srcExpr = assignExpr->getSrc();
|
||||
auto contextualType = destType->getRValueType();
|
||||
|
||||
@@ -644,16 +644,12 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auto resolvedOverload = getResolvedOverload(getLocator()))
|
||||
if (resolvedOverload->Choice.getKind() == OverloadChoiceKind::DynamicMemberLookup)
|
||||
subElementDiagID = diag::assignment_dynamic_property_has_immutable_base;
|
||||
} else if (auto sub = dyn_cast<SubscriptExpr>(diagExpr)) {
|
||||
subElementDiagID = diag::assignment_subscript_has_immutable_base;
|
||||
|
||||
// If the destination is a subscript with a 'dynamicLookup:' label and if
|
||||
// the tuple is implicit, then this was actually a @dynamicMemberLookup
|
||||
// access. Emit a more specific diagnostic.
|
||||
if (sub->getIndex()->isImplicit() &&
|
||||
sub->getArgumentLabels().size() == 1 &&
|
||||
sub->getArgumentLabels().front() == getTypeChecker().Context.Id_dynamicMember)
|
||||
subElementDiagID = diag::assignment_dynamic_property_has_immutable_base;
|
||||
} else {
|
||||
subElementDiagID = diag::assignment_lhs_is_immutable_variable;
|
||||
}
|
||||
@@ -728,23 +724,6 @@ bool AssignmentFailure::diagnoseAsError() {
|
||||
auto *DC = getDC();
|
||||
auto *destExpr = getParentExpr();
|
||||
|
||||
// Assignments to let-properties in delegating initializers will be caught
|
||||
// elsewhere now, so if we see them here, it isn't an assignment problem.
|
||||
if (auto *ctor = dyn_cast<ConstructorDecl>(DC)) {
|
||||
DeclRefExpr *baseRef = nullptr;
|
||||
if (auto *member = dyn_cast<UnresolvedDotExpr>(destExpr)) {
|
||||
baseRef = dyn_cast<DeclRefExpr>(member->getBase());
|
||||
} else if (auto *member = dyn_cast<MemberRefExpr>(destExpr)) {
|
||||
if (auto *load = dyn_cast<LoadExpr>(member->getBase()))
|
||||
baseRef = dyn_cast<DeclRefExpr>(load->getSubExpr());
|
||||
}
|
||||
if (baseRef && baseRef->getDecl() == ctor->getImplicitSelfDecl() &&
|
||||
ctor->getDelegatingOrChainedInitKind(nullptr) ==
|
||||
ConstructorDecl::BodyInitKind::Delegating) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Walk through the destination expression, resolving what the problem is. If
|
||||
// we find a node in the lvalue path that is problematic, this returns it.
|
||||
auto immInfo = resolveImmutableBase(destExpr);
|
||||
|
||||
@@ -2792,7 +2792,7 @@ namespace {
|
||||
return TupleType::get(destTupleTypes, CS.getASTContext());
|
||||
} else {
|
||||
Type destTy = CS.createTypeVariable(CS.getConstraintLocator(expr));
|
||||
CS.addConstraint(ConstraintKind::Bind, CS.getType(expr), LValueType::get(destTy),
|
||||
CS.addConstraint(ConstraintKind::Bind, LValueType::get(destTy), CS.getType(expr),
|
||||
CS.getConstraintLocator(expr));
|
||||
return destTy;
|
||||
}
|
||||
|
||||
@@ -2369,7 +2369,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
|
||||
// If we're converting an lvalue to an inout type, add the missing '&'.
|
||||
conversionsOrFixes.push_back(
|
||||
AddAddressOf::create(*this, getConstraintLocator(locator)));
|
||||
} else if (!isTypeVarOrMember1) {
|
||||
} else {
|
||||
// If we have a concrete type that's an rvalue, "fix" it.
|
||||
conversionsOrFixes.push_back(
|
||||
TreatRValueAsLValue::create(*this, getConstraintLocator(locator)));
|
||||
@@ -2377,7 +2377,10 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
|
||||
}
|
||||
}
|
||||
|
||||
if (attemptFixes && type2->is<LValueType>() && !isTypeVarOrMember1) {
|
||||
if (attemptFixes && type2->is<LValueType>()) {
|
||||
conversionsOrFixes.push_back(
|
||||
TreatRValueAsLValue::create(*this, getConstraintLocator(locator)));
|
||||
} else if (attemptFixes && kind == ConstraintKind::Bind && type1->is<LValueType>()) {
|
||||
conversionsOrFixes.push_back(
|
||||
TreatRValueAsLValue::create(*this, getConstraintLocator(locator)));
|
||||
}
|
||||
@@ -5008,7 +5011,11 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
|
||||
}
|
||||
|
||||
case FixKind::TreatRValueAsLValue: {
|
||||
auto result = matchTypes(LValueType::get(type1), type2,
|
||||
if (type2->is<LValueType>() || type2->is<InOutType>())
|
||||
type1 = LValueType::get(type1);
|
||||
else
|
||||
type2 = LValueType::get(type2);
|
||||
auto result = matchTypes(type1, type2,
|
||||
matchKind, subflags, locator);
|
||||
if (result == SolutionKind::Solved)
|
||||
if (recordFix(fix))
|
||||
|
||||
@@ -53,8 +53,7 @@ value(_) // expected-error{{'_' can only appear in a pattern or on the left side
|
||||
// <rdar://problem/23798944> = vs. == in Swift if string character count statement causes segmentation fault
|
||||
func f23798944() {
|
||||
let s = ""
|
||||
// FIXME: better would be: use of '=' in a boolean context, did you mean '=='?
|
||||
if s.count = 0 { // expected-error {{cannot assign to property: 'count' is a get-only property}}
|
||||
if s.count = 0 { // expected-error {{use of '=' in a boolean context, did you mean '=='?}}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ obj.generic4!(5) // expected-error{{value of type 'Id' (aka 'AnyObject') has no
|
||||
// Find properties via dynamic lookup.
|
||||
var prop1Result : Int = obj.prop1!
|
||||
var prop2Result : String = obj.prop2!
|
||||
obj.prop2 = "hello" // expected-error{{cannot assign to immutable expression of type 'String?'}}
|
||||
obj.prop2 = "hello" // expected-error{{cannot assign to property: 'obj' is immutable}}
|
||||
var protoPropResult : Int = obj.protoProp!
|
||||
|
||||
// Find subscripts via dynamic lookup
|
||||
@@ -290,9 +290,9 @@ let _: String = o[s]
|
||||
let _: String = o[s]!
|
||||
let _: String? = o[s]
|
||||
// FIXME: These should all produce lvalues that we can write through
|
||||
o.s = s // expected-error {{cannot assign to immutable expression of type 'String?'}}
|
||||
o.s = s // expected-error {{cannot assign to property: 'o' is immutable}}
|
||||
o.s! = s // expected-error {{cannot assign through '!': 'o' is immutable}}
|
||||
o[s] = s // expected-error {{cannot assign to immutable expression of type 'String?'}}
|
||||
o[s] = s // expected-error {{cannot assign through subscript: 'o' is immutable}}
|
||||
o[s]! = s // expected-error {{cannot assign through '!': 'o' is immutable}}
|
||||
|
||||
let _: String = o.t
|
||||
@@ -309,7 +309,7 @@ let _: DynamicIUO = o[dyn_iuo]!
|
||||
let _: DynamicIUO = o[dyn_iuo]!!
|
||||
let _: DynamicIUO? = o[dyn_iuo]
|
||||
// FIXME: These should all produce lvalues that we can write through
|
||||
o[dyn_iuo] = dyn_iuo // expected-error {{cannot assign to immutable expression of type 'DynamicIUO??'}}
|
||||
o[dyn_iuo] = dyn_iuo // expected-error {{cannot assign through subscript: 'o' is immutable}}
|
||||
o[dyn_iuo]! = dyn_iuo // expected-error {{cannot assign through '!': 'o' is immutable}}
|
||||
o[dyn_iuo]!! = dyn_iuo // expected-error {{cannot assign through '!': 'o' is immutable}}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ func test(a: Gettable, b: Settable, c: MutGettable, d: NonMutSettable) {
|
||||
|
||||
func test_iuo(a : Gettable!, b : Settable!) {
|
||||
global = a.wyverns
|
||||
a.flavor = global // expected-error {{cannot assign through dynamic lookup property: subscript is get-only}}
|
||||
a.flavor = global // expected-error {{cannot assign through dynamic lookup property: 'a' is a 'let' constant}}
|
||||
|
||||
global = b.flavor
|
||||
b.universal = global // expected-error {{cannot assign through dynamic lookup property: 'b' is a 'let' constant}}
|
||||
|
||||
@@ -314,9 +314,9 @@ func testKeyPathSubscript(readonly: ZwithSubscript, writable: inout ZwithSubscri
|
||||
sink = writable[keyPath: wkp]
|
||||
sink = readonly[keyPath: rkp]
|
||||
sink = writable[keyPath: rkp]
|
||||
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
|
||||
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: 'kp' is a read-only key path}}
|
||||
readonly[keyPath: wkp] = sink // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
|
||||
readonly[keyPath: kp] = sink // expected-error{{cannot assign through subscript: subscript is get-only}}
|
||||
writable[keyPath: kp] = sink // expected-error{{cannot assign through subscript: subscript is get-only}}
|
||||
readonly[keyPath: wkp] = sink // expected-error{{cannot assign through subscript: subscript is get-only}}
|
||||
// FIXME: silently falls back to keypath application, which seems inconsistent
|
||||
writable[keyPath: wkp] = sink
|
||||
// FIXME: silently falls back to keypath application, which seems inconsistent
|
||||
@@ -331,8 +331,8 @@ func testKeyPathSubscript(readonly: ZwithSubscript, writable: inout ZwithSubscri
|
||||
var anySink2 = writable[keyPath: pkp]
|
||||
expect(&anySink2, toHaveType: Exactly<Any>.self)
|
||||
|
||||
readonly[keyPath: pkp] = anySink1 // expected-error{{cannot assign through subscript: 'readonly' is a 'let' constant}}
|
||||
writable[keyPath: pkp] = anySink2 // expected-error{{cannot assign through subscript: 'writable' is immutable}}
|
||||
readonly[keyPath: pkp] = anySink1 // expected-error{{cannot assign through subscript: subscript is get-only}}
|
||||
writable[keyPath: pkp] = anySink2 // expected-error{{cannot assign through subscript: subscript is get-only}}
|
||||
|
||||
let akp: AnyKeyPath = pkp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user