Skip to content

Commit 6e9d97e

Browse files
authored
Merge pull request #81945 from xedin/various-diagnostic-fixes-6.2
[6.2][Diagnostics] A collection of diagnostic fixes/improvements
2 parents 7fb85a3 + d8642fc commit 6e9d97e

36 files changed

+328
-125
lines changed

include/swift/Sema/CSFix.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,11 @@ class ConstraintFix {
560560
return false;
561561
}
562562

563+
template <typename E>
564+
bool directlyAt() const {
565+
return getLocator()->directlyAt<E>();
566+
}
567+
563568
void print(llvm::raw_ostream &Out) const;
564569

565570
SWIFT_DEBUG_DUMP;

include/swift/Sema/ConstraintSystem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3484,6 +3484,15 @@ class ConstraintSystem {
34843484
return nullptr;
34853485
}
34863486

3487+
Expr *getSemanticsProvidingParentExpr(Expr *expr) {
3488+
while (auto *parent = getParentExpr(expr)) {
3489+
if (parent->getSemanticsProvidingExpr() == parent)
3490+
return parent;
3491+
expr = parent;
3492+
}
3493+
return nullptr;
3494+
}
3495+
34873496
/// Retrieve the depth of the given expression.
34883497
std::optional<unsigned> getExprDepth(Expr *expr) {
34893498
if (auto result = getExprDepthAndParent(expr))

lib/Sema/CSDiagnostics.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1114,7 +1114,12 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
11141114
if (!diagnostic)
11151115
return false;
11161116

1117-
emitDiagnosticAt(::getLoc(anchor), *diagnostic, fromType, toType);
1117+
{
1118+
auto diag =
1119+
emitDiagnosticAt(::getLoc(anchor), *diagnostic, fromType, toType);
1120+
(void)tryFixIts(diag);
1121+
}
1122+
11181123
emitNotesForMismatches();
11191124
return true;
11201125
}

lib/Sema/CSSimplify.cpp

Lines changed: 123 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4039,6 +4039,12 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
40394039
getConstraintLocator(locator, {LocatorPathElt::GenericType(type1),
40404040
LocatorPathElt::GenericType(type2)});
40414041

4042+
// Optionals have a lot of special diagnostics and only one
4043+
// generic argument so if we're dealing with one, let's allow
4044+
// `repairFailures` to take care of it.
4045+
if (bound1->getDecl()->isOptionalDecl())
4046+
return matchDeepTypeArguments(*this, subflags, args1, args2, baseLoc);
4047+
40424048
auto argMatchingFlags = subflags;
40434049
// Allow the solver to produce separate fixes while matching
40444050
// key path's root/value to a contextual type instead of the
@@ -4049,13 +4055,6 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
40494055
argMatchingFlags |= TMF_MatchingGenericArguments;
40504056
}
40514057

4052-
// Optionals have a lot of special diagnostics and only one
4053-
// generic argument so if we' re dealing with one, don't produce generic
4054-
// arguments mismatch fixes.
4055-
if (bound1->getDecl()->isOptionalDecl())
4056-
return matchDeepTypeArguments(*this, argMatchingFlags, args1, args2,
4057-
baseLoc);
4058-
40594058
SmallVector<unsigned, 4> mismatches;
40604059
auto result = matchDeepTypeArguments(
40614060
*this, argMatchingFlags, args1, args2, baseLoc,
@@ -4282,7 +4281,8 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
42824281
if (!path.empty()) {
42834282
auto last = path.back();
42844283

4285-
if (last.is<LocatorPathElt::ApplyArgToParam>()) {
4284+
if (last.is<LocatorPathElt::ApplyArgToParam>() ||
4285+
last.is<LocatorPathElt::AutoclosureResult>()) {
42864286
auto proto = protoDecl->getDeclaredInterfaceType();
42874287
// Impact is 2 here because there are two failures
42884288
// 1 - missing conformance and 2 - incorrect argument type.
@@ -4310,6 +4310,15 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
43104310
break;
43114311
}
43124312

4313+
if ((isExpr<ArrayExpr>(anchor) || isExpr<DictionaryExpr>(anchor)) &&
4314+
last.is<LocatorPathElt::TupleElement>()) {
4315+
auto *fix = CollectionElementContextualMismatch::create(
4316+
*this, type1, type2, getConstraintLocator(anchor, path));
4317+
if (recordFix(fix, /*impact=*/2))
4318+
return getTypeMatchFailure(locator);
4319+
break;
4320+
}
4321+
43134322
// TODO(diagnostics): If there are any requirement failures associated
43144323
// with result types which are part of a function type conversion,
43154324
// let's record general conversion mismatch in order for it to capture
@@ -4979,8 +4988,18 @@ repairViaOptionalUnwrap(ConstraintSystem &cs, Type fromType, Type toType,
49794988

49804989
// First, let's check whether it has been determined that
49814990
// it was incorrect to use `?` in this position.
4982-
if (cs.hasFixFor(cs.getConstraintLocator(subExpr), FixKind::RemoveUnwrap))
4991+
if (cs.hasFixFor(cs.getConstraintLocator(subExpr), FixKind::RemoveUnwrap)) {
4992+
if (auto *typeVar =
4993+
fromType->getOptionalObjectType()->getAs<TypeVariableType>()) {
4994+
// If the optional chain is invalid let's unwrap optional and
4995+
// re-introduce the constraint to be solved later once both sides
4996+
// are sufficiently resolved, this would allow to diagnose not only
4997+
// the invalid unwrap but an invalid conversion (if any) as well.
4998+
cs.addConstraint(matchKind, typeVar, toType,
4999+
cs.getConstraintLocator(locator));
5000+
}
49835001
return true;
5002+
}
49845003

49855004
auto type = cs.getType(subExpr);
49865005
// If the type of sub-expression is optional, type of the
@@ -5775,6 +5794,41 @@ bool ConstraintSystem::repairFailures(
57755794
break;
57765795
}
57775796

5797+
// There is no subtyping between object types of inout argument/parameter.
5798+
if (auto argConv = path.back().getAs<LocatorPathElt::ApplyArgToParam>()) {
5799+
// Attempt conversions first.
5800+
if (hasAnyRestriction())
5801+
break;
5802+
5803+
// Unwraps are allowed to preserve l-valueness so we can suggest
5804+
// them here.
5805+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind,
5806+
conversionsOrFixes, locator))
5807+
return true;
5808+
5809+
auto *loc = getConstraintLocator(locator);
5810+
5811+
auto result = matchTypes(lhs, rhs, ConstraintKind::Conversion,
5812+
TMF_ApplyingFix, locator);
5813+
5814+
ConstraintFix *fix = nullptr;
5815+
if (result.isFailure()) {
5816+
// If this is a "destination" argument to a mutating operator
5817+
// like `+=`, let's consider it contextual and only attempt
5818+
// to fix type mismatch on the "source" right-hand side of
5819+
// such operators.
5820+
if (isOperatorArgument(loc) && argConv->getArgIdx() == 0)
5821+
break;
5822+
5823+
fix = AllowArgumentMismatch::create(*this, lhs, rhs, loc);
5824+
} else {
5825+
fix = AllowInOutConversion::create(*this, lhs, rhs, loc);
5826+
}
5827+
5828+
conversionsOrFixes.push_back(fix);
5829+
break;
5830+
}
5831+
57785832
// If this is a problem with result type of a subscript setter,
57795833
// let's re-attempt to repair without l-value conversion in the
57805834
// locator to fix underlying type mismatch.
@@ -5794,7 +5848,7 @@ bool ConstraintSystem::repairFailures(
57945848
break;
57955849
}
57965850

5797-
LLVM_FALLTHROUGH;
5851+
break;
57985852
}
57995853

58005854
case ConstraintLocator::ApplyArgToParam: {
@@ -5874,52 +5928,6 @@ bool ConstraintSystem::repairFailures(
58745928
if (repairByTreatingRValueAsLValue(lhs, rhs))
58755929
break;
58765930

5877-
// If the problem is related to missing unwrap, there is a special
5878-
// fix for that.
5879-
if (lhs->getOptionalObjectType() && !rhs->getOptionalObjectType()) {
5880-
// If this is an attempt to check whether optional conforms to a
5881-
// particular protocol, let's do that before attempting to force
5882-
// unwrap the optional.
5883-
if (hasConversionOrRestriction(ConversionRestrictionKind::Existential))
5884-
break;
5885-
5886-
auto result = matchTypes(lhs->getOptionalObjectType(), rhs, matchKind,
5887-
TMF_ApplyingFix, locator);
5888-
5889-
if (result.isSuccess()) {
5890-
conversionsOrFixes.push_back(
5891-
ForceOptional::create(*this, lhs, rhs, loc));
5892-
break;
5893-
}
5894-
}
5895-
5896-
// There is no subtyping between object types of inout argument/parameter.
5897-
if (elt.getKind() == ConstraintLocator::LValueConversion) {
5898-
auto result = matchTypes(lhs, rhs, ConstraintKind::Conversion,
5899-
TMF_ApplyingFix, locator);
5900-
5901-
ConstraintFix *fix = nullptr;
5902-
if (result.isFailure()) {
5903-
// If this is a "destination" argument to a mutating operator
5904-
// like `+=`, let's consider it contextual and only attempt
5905-
// to fix type mismatch on the "source" right-hand side of
5906-
// such operators.
5907-
if (isOperatorArgument(loc) &&
5908-
loc->findLast<LocatorPathElt::ApplyArgToParam>()->getArgIdx() == 0)
5909-
break;
5910-
5911-
fix = AllowArgumentMismatch::create(*this, lhs, rhs, loc);
5912-
} else {
5913-
fix = AllowInOutConversion::create(*this, lhs, rhs, loc);
5914-
}
5915-
5916-
conversionsOrFixes.push_back(fix);
5917-
break;
5918-
}
5919-
5920-
if (elt.getKind() != ConstraintLocator::ApplyArgToParam)
5921-
break;
5922-
59235931
// If argument in l-value type and parameter is `inout` or a pointer,
59245932
// let's see if it's generic parameter matches and suggest adding explicit
59255933
// `&`.
@@ -6046,7 +6054,7 @@ bool ConstraintSystem::repairFailures(
60466054

60476055
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
60486056
locator))
6049-
break;
6057+
return true;
60506058

60516059
{
60526060
auto *calleeLocator = getCalleeLocator(loc);
@@ -6856,9 +6864,28 @@ bool ConstraintSystem::repairFailures(
68566864
if (!path.empty() && path.back().is<LocatorPathElt::PackElement>())
68576865
path.pop_back();
68586866

6859-
if (!path.empty() && path.back().is<LocatorPathElt::AnyRequirement>()) {
6860-
return repairFailures(lhs, rhs, matchKind, flags, conversionsOrFixes,
6861-
getConstraintLocator(anchor, path));
6867+
if (!path.empty()) {
6868+
if (path.back().is<LocatorPathElt::AnyRequirement>()) {
6869+
return repairFailures(lhs, rhs, matchKind, flags, conversionsOrFixes,
6870+
getConstraintLocator(anchor, path));
6871+
}
6872+
6873+
if (auto argConv = path.back().getAs<LocatorPathElt::ApplyArgToParam>()) {
6874+
auto argIdx = argConv->getArgIdx();
6875+
auto paramIdx = argConv->getParamIdx();
6876+
6877+
auto *argLoc = getConstraintLocator(anchor, path);
6878+
if (auto overload = findSelectedOverloadFor(getCalleeLocator(argLoc))) {
6879+
auto *overloadTy =
6880+
simplifyType(overload->boundType)->castTo<FunctionType>();
6881+
auto *argList = getArgumentList(argLoc);
6882+
ASSERT(argList);
6883+
conversionsOrFixes.push_back(AllowArgumentMismatch::create(
6884+
*this, getType(argList->getExpr(argIdx)),
6885+
overloadTy->getParams()[paramIdx].getPlainType(), argLoc));
6886+
return true;
6887+
}
6888+
}
68626889
}
68636890

68646891
// When the solver sets `TMF_MatchingGenericArguments` it means
@@ -6915,12 +6942,19 @@ bool ConstraintSystem::repairFailures(
69156942
path.pop_back();
69166943

69176944
ConstraintFix *fix = nullptr;
6918-
if (!path.empty() && path.back().is<LocatorPathElt::AnyRequirement>()) {
6945+
auto *fixLoc = getConstraintLocator(anchor, path);
6946+
6947+
if (fixLoc->isLastElement<LocatorPathElt::AnyRequirement>()) {
69196948
fix = fixRequirementFailure(*this, fromType, toType, anchor, path);
6949+
} else if (fixLoc->isLastElement<LocatorPathElt::TupleElement>()) {
6950+
return repairFailures(lhs, rhs, matchKind, flags, conversionsOrFixes,
6951+
fixLoc);
6952+
} else if (!lhs->mayHaveSuperclass() && rhs->isAnyObject()) {
6953+
fix = AllowNonClassTypeToConvertToAnyObject::create(*this, fromType,
6954+
fixLoc);
69206955
} else {
69216956
fix = GenericArgumentsMismatch::create(
6922-
*this, fromType, toType, {genericArgElt.getIndex()},
6923-
getConstraintLocator(anchor, path));
6957+
*this, fromType, toType, {genericArgElt.getIndex()}, fixLoc);
69246958
}
69256959

69266960
if (!fix)
@@ -11410,6 +11444,14 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
1141011444
// `key path` constraint can't be retired until all components
1141111445
// are simplified.
1141211446
addTypeVariableConstraintsToWorkList(memberTypeVar);
11447+
} else if (locator->getAnchor().is<Expr *>() &&
11448+
!getSemanticsProvidingParentExpr(
11449+
getAsExpr(locator->getAnchor()))) {
11450+
// If there are no contextual expressions that could provide
11451+
// a type for the member type variable, let's default it to
11452+
// a placeholder eagerly so it could be propagated to the
11453+
// pattern if necessary.
11454+
recordTypeVariablesAsHoles(memberTypeVar);
1141311455
} else if (locator->isLastElement<LocatorPathElt::PatternMatch>()) {
1141411456
// Let's handle member patterns specifically because they use
1141511457
// equality instead of argument application constraint, so allowing
@@ -15649,14 +15691,31 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1564915691
case FixKind::AllowFunctionSpecialization:
1565015692
case FixKind::IgnoreGenericSpecializationArityMismatch:
1565115693
case FixKind::IgnoreKeyPathSubscriptIndexMismatch:
15652-
case FixKind::AllowMemberRefOnExistential: {
15694+
case FixKind::AllowMemberRefOnExistential:
15695+
case FixKind::AllowNonClassTypeToConvertToAnyObject: {
1565315696
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
1565415697
}
1565515698

1565615699
case FixKind::GenericArgumentsMismatch: {
1565715700
unsigned impact = 1;
1565815701
if (type1->isMarkerExistential() || type2->isMarkerExistential())
1565915702
++impact;
15703+
15704+
// If generic arguments mismatch ends up being recorded on the result
15705+
// of the chain or a try expression it means that there is a contextual
15706+
// conversion mismatch.
15707+
//
15708+
// For optional conversions the solver currently generates a disjunction
15709+
// with two choices - bind and optional-to-optional conversion which is
15710+
// anchored on the contextual expression. If we can get a fix recorded
15711+
// there that would result in a better diagnostic. It's only possible
15712+
// for optional-to-optional choice because it doesn't bind the
15713+
// variable immediately, so we need to downgrade direct fixes to prevent
15714+
// `bind` choice from considered better.
15715+
if (fix->directlyAt<OptionalEvaluationExpr>() ||
15716+
fix->directlyAt<AnyTryExpr>())
15717+
impact += 2;
15718+
1566015719
return recordFix(fix, impact) ? SolutionKind::Error : SolutionKind::Solved;
1566115720
}
1566215721

@@ -15884,7 +15943,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1588415943
case FixKind::DefaultGenericArgument:
1588515944
case FixKind::AllowMutatingMemberOnRValueBase:
1588615945
case FixKind::AllowTupleSplatForSingleParameter:
15887-
case FixKind::AllowNonClassTypeToConvertToAnyObject:
1588815946
case FixKind::SpecifyClosureParameterType:
1588915947
case FixKind::SpecifyClosureReturnType:
1589015948
case FixKind::AddQualifierToAccessTopLevelName:

test/ClangImporter/MixedSource/mixed-target-using-header.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ func testProtocolNamingConflict() {
6666
let a: ConflictingName1?
6767
var b: ConflictingName1Protocol?
6868
b = a // expected-error {{cannot assign value of type 'ConflictingName1?' to type '(any ConflictingName1Protocol)?'}}
69+
// expected-note@-1 {{arguments to generic parameter 'Wrapped' ('ConflictingName1' and 'any ConflictingName1Protocol') are expected to be equal}}
6970
_ = b
7071

7172
let c: ConflictingName2?
7273
var d: ConflictingName2Protocol?
7374
d = c // expected-error {{cannot assign value of type 'ConflictingName2?' to type '(any ConflictingName2Protocol)?'}}
75+
// expected-note@-1 {{arguments to generic parameter 'Wrapped' ('ConflictingName2' and 'any ConflictingName2Protocol') are expected to be equal}}
7476
_ = d
7577
}
7678

test/ClangImporter/cf.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ func testOutParametersGood() {
118118
func testOutParametersBad() {
119119
let fridge: CCRefrigerator?
120120
CCRefrigeratorCreateIndirect(fridge) // expected-error {{cannot convert value of type 'CCRefrigerator?' to expected argument type 'UnsafeMutablePointer<CCRefrigerator?>?'}}
121+
// expected-note@-1 {{arguments to generic parameter 'Wrapped' ('CCRefrigerator' and 'UnsafeMutablePointer<CCRefrigerator?>') are expected to be equal}}
121122

122123
let power: CCPowerSupply?
123124
CCRefrigeratorGetPowerSupplyIndirect(0, power)
@@ -128,21 +129,26 @@ func testOutParametersBad() {
128129
CCRefrigeratorGetItemUnaudited(0, 0, item)
129130
// expected-error@-1:34 {{cannot convert value of type 'Int' to expected argument type 'CCRefrigerator'}}
130131
// expected-error@-2:40 {{cannot convert value of type 'CCItem?' to expected argument type 'UnsafeMutablePointer<Unmanaged<CCItem>?>?'}}
132+
// expected-note@-3 {{arguments to generic parameter 'Wrapped' ('CCItem' and 'UnsafeMutablePointer<Unmanaged<CCItem>?>') are expected to be equal}}
131133
}
132134

133135
func nameCollisions() {
134136
var objc: MyProblematicObject?
135137
var cf: MyProblematicObjectRef?
136138
cf = objc // expected-error {{cannot assign value of type 'MyProblematicObject?' to type 'MyProblematicObjectRef?'}}
139+
// expected-note@-1 {{arguments to generic parameter 'Wrapped' ('MyProblematicObject' and 'MyProblematicObjectRef') are expected to be equal}}
137140
objc = cf // expected-error {{cannot assign value of type 'MyProblematicObjectRef?' to type 'MyProblematicObject?'}}
141+
// expected-note@-1 {{arguments to generic parameter 'Wrapped' ('MyProblematicObjectRef' and 'MyProblematicObject') are expected to be equal}}
138142

139143
var cfAlias: MyProblematicAliasRef?
140144
cfAlias = cf // okay
141145
cf = cfAlias // okay
142146

143147
var otherAlias: MyProblematicAlias?
144148
otherAlias = cfAlias // expected-error {{cannot assign value of type 'MyProblematicAliasRef?' (aka 'Optional<MyProblematicObjectRef>') to type 'MyProblematicAlias?' (aka 'Optional<Float>')}}
149+
// expected-note@-1 {{arguments to generic parameter 'Wrapped' ('MyProblematicAliasRef' (aka 'MyProblematicObjectRef') and 'MyProblematicAlias' (aka 'Float')) are expected to be equal}}
145150
cfAlias = otherAlias // expected-error {{cannot assign value of type 'MyProblematicAlias?' (aka 'Optional<Float>') to type 'MyProblematicAliasRef?' (aka 'Optional<MyProblematicObjectRef>')}}
151+
// expected-note@-1 {{arguments to generic parameter 'Wrapped' ('MyProblematicAlias' (aka 'Float') and 'MyProblematicAliasRef' (aka 'MyProblematicObjectRef')) are expected to be equal}}
146152

147153
func isOptionalFloat(_: inout Optional<Float>) {}
148154
isOptionalFloat(&otherAlias) // okay

test/ClangImporter/ctypes_parse.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ func testFunctionPointers() {
214214

215215
useFunctionPointer2(anotherFP)
216216
sizedFP = fp // expected-error {{cannot assign value of type 'fptr?' (aka 'Optional<@convention(c) (Int32) -> Int32>') to type '(@convention(c) (CInt, CInt, UnsafeMutableRawPointer?) -> Void)?'}}
217+
// expected-note@-1 {{arguments to generic parameter 'Wrapped' ('fptr' (aka '@convention(c) (Int32) -> Int32') and '@convention(c) (CInt, CInt, UnsafeMutableRawPointer?) -> Void'}}
217218
}
218219

219220
func testStructDefaultInit() {

0 commit comments

Comments
 (0)