mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Move another chunk of lvalue diagnostics over to being handled via ConstraintFix.
This commit is contained in:
@@ -850,28 +850,30 @@ void swift::diagnoseSubElementFailure(Expr *destExpr,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto *ICE = dyn_cast<ImplicitConversionExpr>(immInfo.first))
|
if (auto contextualType = CS.getContextualType(immInfo.first)) {
|
||||||
if (auto *LE = dyn_cast<LoadExpr>(ICE->getSubExpr())) {
|
Type neededType = contextualType->getInOutObjectType();
|
||||||
Type actualType = CS.getType(LE);
|
Type actualType = CS.getType(immInfo.first)->getInOutObjectType();
|
||||||
Type neededType = CS.getType(ICE);
|
if (!neededType->isEqual(actualType)) {
|
||||||
|
|
||||||
if (diagID.ID == diag::cannot_pass_rvalue_inout_subelement.ID) {
|
if (diagID.ID == diag::cannot_pass_rvalue_inout_subelement.ID) {
|
||||||
// We have a special diagnostic with tailored wording for this
|
// We have a special diagnostic with tailored wording for this
|
||||||
// common case.
|
// common case.
|
||||||
TC.diagnose(loc, diag::cannot_pass_rvalue_inout_converted,
|
TC.diagnose(loc, diag::cannot_pass_rvalue_inout_converted, actualType,
|
||||||
actualType, neededType)
|
neededType)
|
||||||
.highlight(ICE->getSourceRange());
|
.highlight(immInfo.first->getSourceRange());
|
||||||
|
|
||||||
fixItChangeInoutArgType(LE->getSubExpr(), actualType, neededType, CS);
|
if (auto inoutExpr = dyn_cast<InOutExpr>(immInfo.first))
|
||||||
}
|
fixItChangeInoutArgType(inoutExpr->getSubExpr(), actualType,
|
||||||
else
|
neededType, CS);
|
||||||
|
} else {
|
||||||
TC.diagnose(loc, diagID,
|
TC.diagnose(loc, diagID,
|
||||||
"implicit conversion from '" +
|
"implicit conversion from '" + actualType->getString() +
|
||||||
actualType->getString() + "' to '" +
|
"' to '" + neededType->getString() +
|
||||||
neededType->getString() + "' requires a temporary")
|
"' requires a temporary")
|
||||||
.highlight(ICE->getSourceRange());
|
.highlight(immInfo.first->getSourceRange());
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (auto IE = dyn_cast<IfExpr>(immInfo.first)) {
|
if (auto IE = dyn_cast<IfExpr>(immInfo.first)) {
|
||||||
if (isLoadedLValue(IE)) {
|
if (isLoadedLValue(IE)) {
|
||||||
@@ -6527,9 +6529,7 @@ bool FailureDiagnosis::visitInOutExpr(InOutExpr *IOE) {
|
|||||||
if (auto unwrapped = contextualType->getOptionalObjectType())
|
if (auto unwrapped = contextualType->getOptionalObjectType())
|
||||||
unwrappedType = unwrapped;
|
unwrappedType = unwrapped;
|
||||||
|
|
||||||
PointerTypeKind pointerKind;
|
if (auto pointerEltType = unwrappedType->getAnyPointerElementType()) {
|
||||||
if (auto pointerEltType =
|
|
||||||
unwrappedType->getAnyPointerElementType(pointerKind)) {
|
|
||||||
|
|
||||||
// If the element type is Void, then we allow any input type, since
|
// If the element type is Void, then we allow any input type, since
|
||||||
// everything is convertible to UnsafeRawPointer
|
// everything is convertible to UnsafeRawPointer
|
||||||
@@ -6541,20 +6541,7 @@ bool FailureDiagnosis::visitInOutExpr(InOutExpr *IOE) {
|
|||||||
// Furthermore, if the subexpr type is already known to be an array type,
|
// Furthermore, if the subexpr type is already known to be an array type,
|
||||||
// then we must have an attempt at an array to pointer conversion.
|
// then we must have an attempt at an array to pointer conversion.
|
||||||
if (isKnownToBeArrayType(CS.getType(IOE->getSubExpr()))) {
|
if (isKnownToBeArrayType(CS.getType(IOE->getSubExpr()))) {
|
||||||
// If we're converting to an UnsafeMutablePointer, then the pointer to
|
contextualType = ArraySliceType::get(contextualType);
|
||||||
// the first element is being passed in. The array is ok, so long as
|
|
||||||
// it is mutable.
|
|
||||||
if (pointerKind == PTK_UnsafeMutablePointer) {
|
|
||||||
contextualType = ArraySliceType::get(contextualType);
|
|
||||||
} else if (pointerKind == PTK_UnsafePointer || pointerKind == PTK_UnsafeRawPointer) {
|
|
||||||
// If we're converting to an UnsafePointer, then the programmer
|
|
||||||
// specified an & unnecessarily. Produce a fixit hint to remove it.
|
|
||||||
diagnose(IOE->getLoc(), diag::extra_address_of_unsafepointer,
|
|
||||||
unwrappedType)
|
|
||||||
.highlight(IOE->getSourceRange())
|
|
||||||
.fixItRemove(IOE->getStartLoc());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (contextualType->is<InOutType>()) {
|
} else if (contextualType->is<InOutType>()) {
|
||||||
contextualType = contextualType->getInOutObjectType();
|
contextualType = contextualType->getInOutObjectType();
|
||||||
@@ -6568,21 +6555,11 @@ bool FailureDiagnosis::visitInOutExpr(InOutExpr *IOE) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto subExpr = typeCheckChildIndependently(IOE->getSubExpr(), contextualType,
|
if (!typeCheckChildIndependently(IOE->getSubExpr(), contextualType,
|
||||||
CS.getContextualTypePurpose(),
|
CS.getContextualTypePurpose(),
|
||||||
TCC_AllowLValue);
|
TCC_AllowLValue)) {
|
||||||
if (!subExpr) return true;
|
|
||||||
|
|
||||||
auto subExprType = CS.getType(subExpr);
|
|
||||||
|
|
||||||
// The common cause is that the operand is not an lvalue.
|
|
||||||
if (!subExprType->hasLValueType()) {
|
|
||||||
diagnoseSubElementFailure(subExpr, IOE->getLoc(), CS,
|
|
||||||
diag::cannot_pass_rvalue_inout_subelement,
|
|
||||||
diag::cannot_pass_rvalue_inout);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -535,34 +535,58 @@ bool RValueTreatedAsLValueFailure::diagnose() {
|
|||||||
Expr *diagExpr = getLocator()->getAnchor();
|
Expr *diagExpr = getLocator()->getAnchor();
|
||||||
SourceLoc loc;
|
SourceLoc loc;
|
||||||
|
|
||||||
auto callExpr = dyn_cast<ApplyExpr>(diagExpr);
|
if (auto callExpr = dyn_cast<ApplyExpr>(diagExpr)) {
|
||||||
if (!callExpr)
|
Expr *argExpr = callExpr->getArg();
|
||||||
return false; // currently only creating these for args, so should be
|
loc = callExpr->getFn()->getLoc();
|
||||||
// unreachable
|
|
||||||
|
|
||||||
Expr *argExpr = callExpr->getArg();
|
if (isa<PrefixUnaryExpr>(callExpr) || isa<PostfixUnaryExpr>(callExpr)) {
|
||||||
loc = callExpr->getFn()->getLoc();
|
subElementDiagID = diag::cannot_apply_lvalue_unop_to_subelement;
|
||||||
|
rvalueDiagID = diag::cannot_apply_lvalue_unop_to_rvalue;
|
||||||
|
diagExpr = argExpr;
|
||||||
|
} else if (isa<BinaryExpr>(callExpr)) {
|
||||||
|
subElementDiagID = diag::cannot_apply_lvalue_binop_to_subelement;
|
||||||
|
rvalueDiagID = diag::cannot_apply_lvalue_binop_to_rvalue;
|
||||||
|
auto argTuple = dyn_cast<TupleExpr>(argExpr);
|
||||||
|
diagExpr = argTuple->getElement(0);
|
||||||
|
} else {
|
||||||
|
auto lastPathElement = getLocator()->getPath().back();
|
||||||
|
assert(lastPathElement.getKind() ==
|
||||||
|
ConstraintLocator::PathElementKind::ApplyArgToParam);
|
||||||
|
|
||||||
if (isa<PrefixUnaryExpr>(callExpr) || isa<PostfixUnaryExpr>(callExpr)) {
|
subElementDiagID = diag::cannot_pass_rvalue_inout_subelement;
|
||||||
subElementDiagID = diag::cannot_apply_lvalue_unop_to_subelement;
|
rvalueDiagID = diag::cannot_pass_rvalue_inout;
|
||||||
rvalueDiagID = diag::cannot_apply_lvalue_unop_to_rvalue;
|
if (auto argTuple = dyn_cast<TupleExpr>(argExpr))
|
||||||
diagExpr = argExpr;
|
diagExpr = argTuple->getElement(lastPathElement.getValue());
|
||||||
} else if (isa<BinaryExpr>(callExpr)) {
|
else if (auto parens = dyn_cast<ParenExpr>(argExpr))
|
||||||
subElementDiagID = diag::cannot_apply_lvalue_binop_to_subelement;
|
diagExpr = parens->getSubExpr();
|
||||||
rvalueDiagID = diag::cannot_apply_lvalue_binop_to_rvalue;
|
}
|
||||||
auto argTuple = dyn_cast<TupleExpr>(argExpr);
|
} else if (auto inoutExpr = dyn_cast<InOutExpr>(diagExpr)) {
|
||||||
diagExpr = argTuple->getElement(0);
|
Type type = getConstraintSystem().getType(inoutExpr);
|
||||||
} else {
|
for (auto &restriction : getSolution().ConstraintRestrictions) {
|
||||||
auto lastPathElement = getLocator()->getPath().back();
|
if (restriction.second == ConversionRestrictionKind::ArrayToPointer &&
|
||||||
assert(lastPathElement.getKind() ==
|
restriction.first.first->isEqual(type)) {
|
||||||
ConstraintLocator::PathElementKind::ApplyArgToParam);
|
PointerTypeKind pointerKind;
|
||||||
|
if (restriction.first.second->getAnyPointerElementType(pointerKind) &&
|
||||||
|
(pointerKind == PTK_UnsafePointer ||
|
||||||
|
pointerKind == PTK_UnsafeRawPointer)) {
|
||||||
|
// If we're converting to an UnsafePointer, then the programmer
|
||||||
|
// specified an & unnecessarily. Produce a fixit hint to remove it.
|
||||||
|
emitDiagnostic(inoutExpr->getLoc(),
|
||||||
|
diag::extra_address_of_unsafepointer,
|
||||||
|
restriction.first.second)
|
||||||
|
.highlight(inoutExpr->getSourceRange())
|
||||||
|
.fixItRemove(inoutExpr->getStartLoc());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subElementDiagID = diag::cannot_pass_rvalue_inout_subelement;
|
subElementDiagID = diag::cannot_pass_rvalue_inout_subelement;
|
||||||
rvalueDiagID = diag::cannot_pass_rvalue_inout;
|
rvalueDiagID = diag::cannot_pass_rvalue_inout;
|
||||||
if (auto argTuple = dyn_cast<TupleExpr>(argExpr))
|
loc = diagExpr->getLoc();
|
||||||
diagExpr = argTuple->getElement(lastPathElement.getValue());
|
diagExpr = inoutExpr->getSubExpr();
|
||||||
else if (auto parens = dyn_cast<ParenExpr>(argExpr))
|
} else {
|
||||||
diagExpr = parens->getSubExpr();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnoseSubElementFailure(diagExpr, loc, getConstraintSystem(),
|
diagnoseSubElementFailure(diagExpr, loc, getConstraintSystem(),
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ protected:
|
|||||||
|
|
||||||
DeclContext *getDC() const { return getConstraintSystem().DC; }
|
DeclContext *getDC() const { return getConstraintSystem().DC; }
|
||||||
|
|
||||||
|
const Solution &getSolution() const { return solution; }
|
||||||
|
|
||||||
Optional<SelectedOverload>
|
Optional<SelectedOverload>
|
||||||
getOverloadChoiceIfAvailable(ConstraintLocator *locator) const {
|
getOverloadChoiceIfAvailable(ConstraintLocator *locator) const {
|
||||||
return solution.getOverloadChoiceIfAvailable(locator);
|
return solution.getOverloadChoiceIfAvailable(locator);
|
||||||
|
|||||||
@@ -2409,7 +2409,7 @@ namespace {
|
|||||||
auto result = InOutType::get(lvalue);
|
auto result = InOutType::get(lvalue);
|
||||||
CS.addConstraint(ConstraintKind::Conversion,
|
CS.addConstraint(ConstraintKind::Conversion,
|
||||||
CS.getType(expr->getSubExpr()), bound,
|
CS.getType(expr->getSubExpr()), bound,
|
||||||
CS.getConstraintLocator(expr->getSubExpr()));
|
CS.getConstraintLocator(expr));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2450,6 +2450,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
|
|||||||
TreatRValueAsLValue::create(*this, getConstraintLocator(locator)));
|
TreatRValueAsLValue::create(*this, getConstraintLocator(locator)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type2->is<LValueType>() && !isTypeVarOrMember1) {
|
||||||
|
conversionsOrFixes.push_back(
|
||||||
|
TreatRValueAsLValue::create(*this, getConstraintLocator(locator)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conversionsOrFixes.empty()) {
|
if (conversionsOrFixes.empty()) {
|
||||||
@@ -4659,11 +4664,11 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
|
|||||||
addContextualScore();
|
addContextualScore();
|
||||||
// Unwrap an inout type.
|
// Unwrap an inout type.
|
||||||
auto obj1 = type1->getInOutObjectType();
|
auto obj1 = type1->getInOutObjectType();
|
||||||
|
|
||||||
obj1 = getFixedTypeRecursive(obj1, false, false);
|
obj1 = getFixedTypeRecursive(obj1, false, false);
|
||||||
|
|
||||||
auto t2 = type2->getDesugaredType();
|
auto t2 = type2->getDesugaredType();
|
||||||
|
|
||||||
auto baseType1 = getFixedTypeRecursive(*isArrayType(obj1), false, false);
|
auto baseType1 = getFixedTypeRecursive(*isArrayType(obj1), false, false);
|
||||||
auto baseType2 = getBaseTypeForPointer(*this, t2);
|
auto baseType2 = getBaseTypeForPointer(*this, t2);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user