Skip to content

Commit 6d02fb7

Browse files
authored
Merge pull request swiftlang#28057 from xedin/assign-diags
[Diagnostics] Port the rest of assignment diagnostics to the new framework
2 parents 963c3e0 + 2dd87c7 commit 6d02fb7

25 files changed

+528
-323
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,10 @@ ERROR(cannot_convert_subscript_assign_protocol,none,
551551
ERROR(cannot_convert_subscript_assign_nil,none,
552552
"'nil' cannot be assigned to subscript of type %0", (Type))
553553

554+
NOTE(cannot_convert_candidate_result_to_contextual_type,none,
555+
"%0 produces %1, not the expected contextual result type %2",
556+
(DeclName, Type, Type))
557+
554558
// for ... in expression
555559
ERROR(cannot_convert_sequence_element_value,none,
556560
"cannot convert sequence element type %0 to expected type %1",

lib/Sema/CSDiag.cpp

Lines changed: 25 additions & 280 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,6 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
282282

283283
bool visitSubscriptExpr(SubscriptExpr *SE);
284284
bool visitApplyExpr(ApplyExpr *AE);
285-
bool visitAssignExpr(AssignExpr *AE);
286-
bool visitInOutExpr(InOutExpr *IOE);
287285
bool visitCoerceExpr(CoerceExpr *CE);
288286
bool visitIfExpr(IfExpr *IE);
289287
bool visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E);
@@ -1296,55 +1294,6 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
12961294
// Diagnose assigning variable to itself.
12971295
//===----------------------------------------------------------------------===//
12981296

1299-
static Decl *findSimpleReferencedDecl(const Expr *E) {
1300-
if (auto *LE = dyn_cast<LoadExpr>(E))
1301-
E = LE->getSubExpr();
1302-
1303-
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
1304-
return DRE->getDecl();
1305-
1306-
return nullptr;
1307-
}
1308-
1309-
static std::pair<Decl *, Decl *> findReferencedDecl(const Expr *E) {
1310-
E = E->getValueProvidingExpr();
1311-
1312-
if (auto *LE = dyn_cast<LoadExpr>(E))
1313-
return findReferencedDecl(LE->getSubExpr());
1314-
1315-
if (auto *AE = dyn_cast<AssignExpr>(E))
1316-
return findReferencedDecl(AE->getDest());
1317-
1318-
if (auto *D = findSimpleReferencedDecl(E))
1319-
return std::make_pair(nullptr, D);
1320-
1321-
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
1322-
if (auto *BaseDecl = findSimpleReferencedDecl(MRE->getBase()))
1323-
return std::make_pair(BaseDecl, MRE->getMember().getDecl());
1324-
}
1325-
1326-
return std::make_pair(nullptr, nullptr);
1327-
}
1328-
1329-
bool TypeChecker::diagnoseSelfAssignment(const Expr *E) {
1330-
auto AE = dyn_cast<AssignExpr>(E);
1331-
if (!AE)
1332-
return false;
1333-
1334-
auto LHSDecl = findReferencedDecl(AE->getDest());
1335-
auto RHSDecl = findReferencedDecl(AE->getSrc());
1336-
1337-
if (LHSDecl.second && LHSDecl == RHSDecl) {
1338-
diagnose(AE->getLoc(), LHSDecl.first ? diag::self_assignment_prop
1339-
: diag::self_assignment_var)
1340-
.highlight(AE->getDest()->getSourceRange())
1341-
.highlight(AE->getSrc()->getSourceRange());
1342-
return true;
1343-
}
1344-
1345-
return false;
1346-
}
1347-
13481297
static bool isSymmetricBinaryOperator(const CalleeCandidateInfo &CCI) {
13491298
// If we don't have at least one known candidate, don't trigger.
13501299
if (CCI.candidates.empty()) return false;
@@ -3179,113 +3128,6 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
31793128
return true;
31803129
}
31813130

3182-
bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) {
3183-
// Diagnose obvious assignments to literals.
3184-
if (isa<LiteralExpr>(assignExpr->getDest()->getValueProvidingExpr())) {
3185-
diagnose(assignExpr->getLoc(), diag::cannot_assign_to_literal);
3186-
return true;
3187-
}
3188-
3189-
// Situation like `var foo = &bar` didn't get diagnosed early
3190-
// because originally its parent is a `SequenceExpr` which hasn't
3191-
// been folded yet, and could represent an operator which accepts
3192-
// `inout` arguments.
3193-
if (auto *AddrOf = dyn_cast<InOutExpr>(assignExpr->getSrc())) {
3194-
diagnose(AddrOf->getLoc(), diag::extraneous_address_of);
3195-
return true;
3196-
}
3197-
3198-
if (CS.TC.diagnoseSelfAssignment(assignExpr))
3199-
return true;
3200-
3201-
// Type check the destination first, so we can coerce the source to it.
3202-
auto destExpr = typeCheckChildIndependently(assignExpr->getDest(),
3203-
TCC_AllowLValue);
3204-
if (!destExpr) return true;
3205-
3206-
auto destType = CS.getType(destExpr);
3207-
if (destType->is<UnresolvedType>() || destType->hasTypeVariable()) {
3208-
// Look closer into why destination has unresolved types since such
3209-
// means that destination has diagnosable structural problems, and it's
3210-
// better to diagnose destination (if possible) before moving on to
3211-
// the source of the assignment.
3212-
destExpr = typeCheckChildIndependently(
3213-
destExpr, TCC_AllowLValue | TCC_ForceRecheck, false);
3214-
if (!destExpr)
3215-
return true;
3216-
3217-
// If re-checking destination didn't produce diagnostic, let's just type
3218-
// check the source without contextual information. If it succeeds, then we
3219-
// win, but if it fails, we'll have to diagnose this another way.
3220-
return !typeCheckChildIndependently(assignExpr->getSrc());
3221-
}
3222-
3223-
// If the result type is a non-lvalue, then we are failing because it is
3224-
// immutable and that's not a great thing to assign to.
3225-
if (!destType->hasLValueType()) {
3226-
// If the destination is a subscript, the problem may actually be that we
3227-
// incorrectly decided on a get-only subscript overload, and we may be able
3228-
// to come up with a better diagnosis by looking only at subscript candidates
3229-
// that are set-able.
3230-
if (auto subscriptExpr = dyn_cast<SubscriptExpr>(destExpr)) {
3231-
if (diagnoseSubscriptErrors(subscriptExpr, /* inAssignmentDestination = */ true))
3232-
return true;
3233-
}
3234-
// Member ref assignment errors detected elsewhere, so not an assignment issue if found here.
3235-
// The remaining exception involves mutable pointer conversions which aren't always caught elsewhere.
3236-
PointerTypeKind ptk;
3237-
if (!isa<MemberRefExpr>(destExpr) || CS.getType(destExpr)
3238-
->lookThroughAllOptionalTypes()
3239-
->getAnyPointerElementType(ptk)) {
3240-
AssignmentFailure failure(destExpr, CS, assignExpr->getLoc());
3241-
if (failure.diagnoseAsError())
3242-
return true;
3243-
}
3244-
}
3245-
3246-
auto *srcExpr = assignExpr->getSrc();
3247-
auto contextualType = destType->getRValueType();
3248-
auto contextualTypePurpose = isa<SubscriptExpr>(destExpr)
3249-
? CTP_SubscriptAssignSource
3250-
: CTP_AssignSource;
3251-
// Let's try to type-check assignment source expression without using
3252-
// destination as a contextual type, that allows us to diagnose
3253-
// contextual problems related to source much easier.
3254-
//
3255-
// If source expression requires contextual type to be present,
3256-
// let's avoid this step because it's always going to fail.
3257-
{
3258-
auto *srcExpr = assignExpr->getSrc();
3259-
ExprTypeSaverAndEraser eraser(srcExpr);
3260-
3261-
ConcreteDeclRef ref = nullptr;
3262-
auto type = getTypeOfExpressionWithoutApplying(srcExpr, CS.DC, ref);
3263-
3264-
if (type && !type->isEqual(contextualType))
3265-
return diagnoseContextualConversionError(
3266-
assignExpr->getSrc(), contextualType, contextualTypePurpose);
3267-
}
3268-
3269-
srcExpr = typeCheckChildIndependently(assignExpr->getSrc(), contextualType,
3270-
contextualTypePurpose);
3271-
if (!srcExpr)
3272-
return true;
3273-
3274-
// If we are assigning to _ and have unresolved types on the RHS, then we have
3275-
// an ambiguity problem.
3276-
if (isa<DiscardAssignmentExpr>(destExpr->getSemanticsProvidingExpr()) &&
3277-
CS.getType(srcExpr)->hasUnresolvedType()) {
3278-
diagnoseAmbiguity(srcExpr);
3279-
return true;
3280-
}
3281-
3282-
return false;
3283-
}
3284-
3285-
bool FailureDiagnosis::visitInOutExpr(InOutExpr *IOE) {
3286-
return false;
3287-
}
3288-
32893131
bool FailureDiagnosis::visitCoerceExpr(CoerceExpr *CE) {
32903132
// Coerce the input to whatever type is specified by the CoerceExpr.
32913133
auto expr = typeCheckChildIndependently(CE->getSubExpr(),
@@ -3797,128 +3639,7 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
37973639
return true;
37983640
}
37993641

3800-
auto *argExpr = E->getArgument();
3801-
auto candidateArgTy = candidateInfo[0].getArgumentType(CS.getASTContext());
3802-
3803-
// Depending on how we matched, produce tailored diagnostics.
3804-
switch (candidateInfo.closeness) {
3805-
case CC_SelfMismatch: // Self argument mismatches.
3806-
llvm_unreachable("These aren't produced by filterContextualMemberList");
3807-
return false;
3808-
3809-
case CC_NonLValueInOut: // First argument is inout but no lvalue present.
3810-
case CC_OneArgumentMismatch: // All arguments except one match.
3811-
case CC_OneArgumentNearMismatch:
3812-
case CC_OneGenericArgumentMismatch:
3813-
case CC_OneGenericArgumentNearMismatch:
3814-
case CC_GenericNonsubstitutableMismatch:
3815-
case CC_ArgumentNearMismatch: // Argument list mismatch.
3816-
case CC_ArgumentMismatch: // Argument list mismatch.
3817-
// Candidate filtering can produce these now, but they can't
3818-
// be properly diagnosed here at the moment.
3819-
return false;
3820-
3821-
case CC_ExactMatch: { // This is a perfect match for the arguments.
3822-
3823-
// If we have an exact match, then we must have an argument list, check
3824-
// it.
3825-
if (candidateArgTy) {
3826-
assert(argExpr && "Exact match without argument?");
3827-
if (!typeCheckArgumentChildIndependently(argExpr, candidateArgTy,
3828-
candidateInfo))
3829-
return true;
3830-
}
3831-
3832-
// If the argument is a match, then check the result type. We might have
3833-
// looked up a contextual member whose result type disagrees with the
3834-
// expected result type.
3835-
auto resultTy = candidateInfo[0].getResultType();
3836-
if (!resultTy)
3837-
resultTy = candidateInfo[0].getType();
3838-
3839-
if (resultTy && !CS.getContextualType()->is<UnboundGenericType>() &&
3840-
!CS.TC.isConvertibleTo(resultTy, CS.getContextualType(), CS.DC)) {
3841-
diagnose(E->getNameLoc(), diag::expected_result_in_contextual_member,
3842-
E->getName(), resultTy, CS.getContextualType());
3843-
return true;
3844-
}
3845-
3846-
// Otherwise, this is an exact match, return false to diagnose this as an
3847-
// ambiguity. It must be some other problem, such as failing to infer a
3848-
// generic argument on the enum type.
3849-
return false;
3850-
}
3851-
3852-
case CC_Unavailable:
3853-
case CC_Inaccessible:
3854-
// Diagnose some simple and common errors.
3855-
return candidateInfo.diagnoseSimpleErrors(E);
3856-
3857-
case CC_ArgumentLabelMismatch:
3858-
case CC_ArgumentCountMismatch: {
3859-
// If we have no argument, the candidates must have expected one.
3860-
if (!argExpr) {
3861-
if (!candidateArgTy)
3862-
return false; // Candidate must be incorrect for some other reason.
3863-
3864-
// Pick one of the arguments that are expected as an exemplar.
3865-
if (candidateArgTy->isVoid()) {
3866-
// If this member is () -> T, suggest adding parentheses.
3867-
diagnose(E->getNameLoc(), diag::expected_parens_in_contextual_member,
3868-
E->getName())
3869-
.fixItInsertAfter(E->getEndLoc(), "()");
3870-
} else {
3871-
diagnose(E->getNameLoc(),
3872-
diag::expected_argument_in_contextual_member, E->getName(),
3873-
candidateArgTy);
3874-
}
3875-
return true;
3876-
}
3877-
3878-
assert(argExpr && candidateArgTy && "Exact match without an argument?");
3879-
return diagnoseSingleCandidateFailures(candidateInfo, E, argExpr,
3880-
E->getArgumentLabels());
3881-
}
3882-
3883-
case CC_GeneralMismatch: { // Something else is wrong.
3884-
// If an argument value was specified, but this member expects no
3885-
// arguments,
3886-
// then we fail with a nice error message.
3887-
if (!candidateArgTy) {
3888-
auto kind = candidateInfo[0].getDecl()->getDescriptiveKind();
3889-
bool isVoid = CS.getType(argExpr)->isVoid();
3890-
auto argumentRange = E->getArgument()->getSourceRange();
3891-
if (kind == DescriptiveDeclKind::EnumElement) {
3892-
if (isVoid) {
3893-
diagnose(E->getNameLoc(), diag::unexpected_arguments_in_enum_case,
3894-
E->getName())
3895-
.fixItRemove(argumentRange);
3896-
} else {
3897-
diagnose(E->getNameLoc(), diag::unexpected_arguments_in_enum_case,
3898-
E->getName())
3899-
.highlight(argumentRange);
3900-
}
3901-
} else {
3902-
if (isVoid) {
3903-
diagnose(E->getNameLoc(),
3904-
diag::unexpected_arguments_in_contextual_member, kind,
3905-
E->getName())
3906-
.fixItRemove(argumentRange);
3907-
} else {
3908-
diagnose(E->getNameLoc(),
3909-
diag::unexpected_arguments_in_contextual_member, kind,
3910-
E->getName())
3911-
.highlight(argumentRange);
3912-
}
3913-
}
3914-
return true;
3915-
}
3916-
3917-
return false;
3918-
}
3919-
}
3920-
3921-
llvm_unreachable("all cases should be handled");
3642+
return false;
39223643
};
39233644

39243645
return diagnoseMemberFailures(E, nullptr, memberConstraint->getKind(),
@@ -4520,6 +4241,30 @@ diagnoseAmbiguousMultiStatementClosure(ClosureExpr *closure) {
45204241

45214242
/// Emit an ambiguity diagnostic about the specified expression.
45224243
void FailureDiagnosis::diagnoseAmbiguity(Expr *E) {
4244+
if (auto *assignment = dyn_cast<AssignExpr>(E)) {
4245+
if (isa<DiscardAssignmentExpr>(assignment->getDest())) {
4246+
auto *srcExpr = assignment->getSrc();
4247+
4248+
bool diagnosedInvalidUseOfDiscardExpr = false;
4249+
srcExpr->forEachChildExpr([&](Expr *expr) -> Expr * {
4250+
if (auto *DAE = dyn_cast<DiscardAssignmentExpr>(expr)) {
4251+
diagnose(DAE->getLoc(), diag::discard_expr_outside_of_assignment)
4252+
.highlight(srcExpr->getSourceRange());
4253+
diagnosedInvalidUseOfDiscardExpr = true;
4254+
return nullptr;
4255+
}
4256+
4257+
return expr;
4258+
});
4259+
4260+
if (diagnosedInvalidUseOfDiscardExpr)
4261+
return;
4262+
4263+
diagnoseAmbiguity(srcExpr);
4264+
return;
4265+
}
4266+
}
4267+
45234268
// Unresolved/Anonymous ClosureExprs are common enough that we should give
45244269
// them tailored diagnostics.
45254270
if (auto CE = dyn_cast<ClosureExpr>(E->getValueProvidingExpr())) {

0 commit comments

Comments
 (0)