Skip to content

Commit f9a1ab2

Browse files
committed
[ConstraintSystem] Port tuple type mismatches to the new framework
1 parent fb2346d commit f9a1ab2

File tree

14 files changed

+124
-114
lines changed

14 files changed

+124
-114
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -956,9 +956,6 @@ ERROR(tuple_types_not_convertible_nelts,none,
956956
"%0 is not convertible to %1, "
957957
"tuples have a different number of elements", (Type, Type))
958958

959-
ERROR(tuple_types_not_convertible,none,
960-
"tuple type %0 is not convertible to tuple %1", (Type, Type))
961-
962959
ERROR(invalid_force_unwrap,none,
963960
"cannot force unwrap value of non-optional type %0", (Type))
964961
ERROR(invalid_optional_chain,none,

lib/Sema/CSDiag.cpp

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,7 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
255255
bool visitExpr(Expr *E);
256256
bool visitIdentityExpr(IdentityExpr *E);
257257
bool visitTryExpr(TryExpr *E);
258-
bool visitTupleExpr(TupleExpr *E);
259-
258+
260259
bool visitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
261260
bool visitUnresolvedDotExpr(UnresolvedDotExpr *UDE);
262261
bool visitArrayExpr(ArrayExpr *E);
@@ -2936,58 +2935,6 @@ bool FailureDiagnosis::visitUnresolvedDotExpr(UnresolvedDotExpr *UDE) {
29362935
locator);
29372936
}
29382937

2939-
/// A TupleExpr propagate contextual type information down to its children and
2940-
/// can be erroneous when there is a label mismatch etc.
2941-
bool FailureDiagnosis::visitTupleExpr(TupleExpr *TE) {
2942-
// If we know the requested argType to use, use computeTupleShuffle to produce
2943-
// the shuffle of input arguments to destination values. It requires a
2944-
// TupleType to compute the mapping from argExpr. Conveniently, it doesn't
2945-
// care about the actual types though, so we can just use 'void' for them.
2946-
if (!CS.getContextualType() || !CS.getContextualType()->is<TupleType>())
2947-
return visitExpr(TE);
2948-
2949-
auto contextualTT = CS.getContextualType()->castTo<TupleType>();
2950-
2951-
SmallVector<TupleTypeElt, 4> ArgElts;
2952-
auto voidTy = CS.getASTContext().TheEmptyTupleType;
2953-
2954-
for (unsigned i = 0, e = TE->getNumElements(); i != e; ++i)
2955-
ArgElts.push_back({ voidTy, TE->getElementName(i) });
2956-
auto TEType = TupleType::get(ArgElts, CS.getASTContext());
2957-
2958-
if (!TEType->is<TupleType>())
2959-
return visitExpr(TE);
2960-
2961-
SmallVector<unsigned, 4> sources;
2962-
2963-
// If the shuffle is invalid, then there is a type error. We could diagnose
2964-
// it specifically here, but the general logic does a fine job so we let it
2965-
// do it.
2966-
if (computeTupleShuffle(TEType->castTo<TupleType>()->getElements(),
2967-
contextualTT->getElements(), sources))
2968-
return visitExpr(TE);
2969-
2970-
// If we got a correct shuffle, we can perform the analysis of all of
2971-
// the input elements, with their expected types.
2972-
for (unsigned i = 0, e = sources.size(); i != e; ++i) {
2973-
// Otherwise, it must match the corresponding expected argument type.
2974-
unsigned inArgNo = sources[i];
2975-
2976-
TCCOptions options;
2977-
if (contextualTT->getElement(i).isInOut())
2978-
options |= TCC_AllowLValue;
2979-
2980-
auto actualType = contextualTT->getElementType(i);
2981-
auto exprResult =
2982-
typeCheckChildIndependently(TE->getElement(inArgNo), actualType,
2983-
CS.getContextualTypePurpose(), options);
2984-
// If there was an error type checking this argument, then we're done.
2985-
if (!exprResult) return true;
2986-
}
2987-
2988-
return false;
2989-
}
2990-
29912938
/// An IdentityExpr doesn't change its argument, but it *can* propagate its
29922939
/// contextual type information down.
29932940
bool FailureDiagnosis::visitIdentityExpr(IdentityExpr *E) {

lib/Sema/CSDiagnostics.cpp

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,7 @@ FailureDiagnostic::getChoiceFor(ConstraintLocator *locator) const {
131131
return getOverloadChoiceIfAvailable(cs.getCalleeLocator(locator));
132132
}
133133

134-
Type FailureDiagnostic::resolveInterfaceType(Type type,
135-
bool reconstituteSugar) const {
136-
auto &cs = getConstraintSystem();
134+
static Type resolveInterfaceType(ConstraintSystem &cs, Type type) {
137135
auto resolvedType = type.transform([&](Type type) -> Type {
138136
if (auto *tvt = type->getAs<TypeVariableType>()) {
139137
// If this type variable is for a generic parameter, return that.
@@ -142,13 +140,13 @@ Type FailureDiagnostic::resolveInterfaceType(Type type,
142140

143141
// Otherwise resolve its fixed type, mapped out of context.
144142
if (auto fixed = cs.getFixedType(tvt))
145-
return resolveInterfaceType(fixed->mapTypeOutOfContext());
143+
return resolveInterfaceType(cs, fixed->mapTypeOutOfContext());
146144

147145
return cs.getRepresentative(tvt);
148146
}
149147
if (auto *dmt = type->getAs<DependentMemberType>()) {
150148
// For a dependent member, first resolve the base.
151-
auto newBase = resolveInterfaceType(dmt->getBase());
149+
auto newBase = resolveInterfaceType(cs, dmt->getBase());
152150

153151
// Then reconstruct using its associated type.
154152
assert(dmt->getAssocType());
@@ -158,8 +156,7 @@ Type FailureDiagnostic::resolveInterfaceType(Type type,
158156
});
159157

160158
assert(!resolvedType->hasArchetype());
161-
return reconstituteSugar ? resolvedType->reconstituteSugar(/*recursive*/ true)
162-
: resolvedType;
159+
return resolvedType;
163160
}
164161

165162
/// Given an apply expr, returns true if it is expected to have a direct callee
@@ -192,8 +189,8 @@ static bool shouldHaveDirectCalleeOverload(const CallExpr *callExpr) {
192189
}
193190

194191
Optional<FunctionArgApplyInfo>
195-
FailureDiagnostic::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
196-
auto &cs = getConstraintSystem();
192+
FailureDiagnostic::getFunctionArgApplyInfo(ConstraintSystem &cs,
193+
ConstraintLocator *locator) {
197194
auto *anchor = locator->getAnchor();
198195
auto path = locator->getPath();
199196

@@ -225,7 +222,8 @@ FailureDiagnostic::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
225222

226223
Optional<OverloadChoice> choice;
227224
Type rawFnType;
228-
if (auto overload = getChoiceFor(argLocator)) {
225+
auto *calleeLocator = cs.getCalleeLocator(argLocator);
226+
if (auto overload = cs.findSelectedOverloadFor(calleeLocator)) {
229227
// If we have resolved an overload for the callee, then use that to get the
230228
// function type and callee.
231229
choice = overload->choice;
@@ -249,7 +247,8 @@ FailureDiagnostic::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
249247

250248
// Try to resolve the function type by loading lvalues and looking through
251249
// optional types, which can occur for expressions like `fn?(5)`.
252-
auto *fnType = resolveType(rawFnType)
250+
auto *fnType = cs.simplifyType(rawFnType)
251+
->getRValueType()
253252
->lookThroughAllOptionalTypes()
254253
->getAs<FunctionType>();
255254
if (!fnType)
@@ -280,13 +279,14 @@ FailureDiagnostic::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
280279
(void)fn;
281280
}
282281
} else {
283-
fnInterfaceType = resolveInterfaceType(rawFnType);
282+
fnInterfaceType = resolveInterfaceType(cs, rawFnType);
284283
}
285284

286285
auto argIdx = applyArgElt->getArgIdx();
287286
auto paramIdx = applyArgElt->getParamIdx();
288287

289-
return FunctionArgApplyInfo(cs, argExpr, argIdx, getType(argExpr),
288+
return FunctionArgApplyInfo(cs, argExpr, argIdx,
289+
cs.simplifyType(cs.getType(argExpr)),
290290
paramIdx, fnInterfaceType, fnType, callee);
291291
}
292292

@@ -929,7 +929,8 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const {
929929
// Let's check whether this is a function parameter passed
930930
// as an argument to another function which accepts @escaping
931931
// function at that position.
932-
if (auto argApplyInfo = getFunctionArgApplyInfo(getLocator())) {
932+
auto &cs = getConstraintSystem();
933+
if (auto argApplyInfo = getFunctionArgApplyInfo(cs, getLocator())) {
933934
auto paramInterfaceTy = argApplyInfo->getParamInterfaceType();
934935
if (paramInterfaceTy->isTypeParameter()) {
935936
auto diagnoseGenericParamFailure = [&](GenericTypeParamDecl *decl) {
@@ -1137,7 +1138,8 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt(
11371138
if (isa<InOutExpr>(anchor))
11381139
return;
11391140

1140-
if (auto argApplyInfo = getFunctionArgApplyInfo(getLocator()))
1141+
auto &cs = getConstraintSystem();
1142+
if (auto argApplyInfo = getFunctionArgApplyInfo(cs, getLocator()))
11411143
if (argApplyInfo->getParameterFlags().isInOut())
11421144
return;
11431145

@@ -2963,8 +2965,12 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
29632965
bool TupleContextualFailure::diagnoseAsError() {
29642966
auto diagnostic = isNumElementsMismatch()
29652967
? diag::tuple_types_not_convertible_nelts
2966-
: diag::tuple_types_not_convertible;
2967-
emitDiagnostic(getAnchor()->getLoc(), diagnostic, getFromType(), getToType());
2968+
: getDiagnosticFor(getContextualTypePurpose(),
2969+
/*forProtocol=*/false);
2970+
if (!diagnostic)
2971+
return false;
2972+
2973+
emitDiagnostic(getAnchor()->getLoc(), *diagnostic, getFromType(), getToType());
29682974
return true;
29692975
}
29702976

@@ -3796,7 +3802,7 @@ bool MissingArgumentsFailure::diagnoseAsError() {
37963802
// foo(bar) // `() -> Void` vs. `(Int) -> Void`
37973803
// ```
37983804
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
3799-
auto info = *getFunctionArgApplyInfo(locator);
3805+
auto info = *getFunctionArgApplyInfo(cs, locator);
38003806

38013807
auto *argExpr = info.getArgExpr();
38023808
emitDiagnostic(argExpr->getLoc(), diag::cannot_convert_argument_value,
@@ -4012,7 +4018,7 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) {
40124018
auto *locator = getLocator();
40134019
if (locator->isForContextualType()) {
40144020
funcType = cs.getContextualType()->getAs<FunctionType>();
4015-
} else if (auto info = getFunctionArgApplyInfo(locator)) {
4021+
} else if (auto info = getFunctionArgApplyInfo(cs, locator)) {
40164022
funcType = info->getParamType()->getAs<FunctionType>();
40174023
} else if (locator->isLastElement<LocatorPathElt::ClosureResult>()) {
40184024
// Based on the locator we know this this is something like this:
@@ -4725,7 +4731,8 @@ SourceLoc InvalidUseOfAddressOf::getLoc() const {
47254731
}
47264732

47274733
bool InvalidUseOfAddressOf::diagnoseAsError() {
4728-
if (auto argApplyInfo = getFunctionArgApplyInfo(getLocator())) {
4734+
auto &cs = getConstraintSystem();
4735+
if (auto argApplyInfo = getFunctionArgApplyInfo(cs, getLocator())) {
47294736
if (!argApplyInfo->getParameterFlags().isInOut()) {
47304737
auto anchor = getAnchor();
47314738
emitDiagnostic(anchor->getLoc(), diag::extra_address_of, getToType())
@@ -5245,18 +5252,19 @@ bool ThrowingFunctionConversionFailure::diagnoseAsError() {
52455252
}
52465253

52475254
bool InOutConversionFailure::diagnoseAsError() {
5255+
auto &cs = getConstraintSystem();
52485256
auto *anchor = getAnchor();
52495257
auto *locator = getLocator();
52505258
auto path = locator->getPath();
52515259

52525260
if (!path.empty() &&
52535261
path.back().getKind() == ConstraintLocator::FunctionArgument) {
5254-
if (auto argApplyInfo = getFunctionArgApplyInfo(locator)) {
5262+
if (auto argApplyInfo = getFunctionArgApplyInfo(cs, locator)) {
52555263
emitDiagnostic(anchor->getLoc(), diag::cannot_convert_argument_value,
52565264
argApplyInfo->getArgType(), argApplyInfo->getParamType());
52575265
} else {
52585266
assert(locator->findLast<LocatorPathElt::ContextualType>());
5259-
auto contextualType = getConstraintSystem().getContextualType();
5267+
auto contextualType = cs.getContextualType();
52605268
auto purpose = getContextualTypePurpose();
52615269
auto diagnostic = getDiagnosticFor(purpose, /*forProtocol=*/false);
52625270

lib/Sema/CSDiagnostics.h

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ class FailureDiagnostic {
9191
Type getType(Expr *expr, bool wantRValue = true) const;
9292
Type getType(const TypeLoc &loc, bool wantRValue = true) const;
9393

94+
/// For a given locator describing a function argument conversion, or a
95+
/// constraint within an argument conversion, returns information about the
96+
/// application of the argument to its parameter. If the locator is not
97+
/// for an argument conversion, returns \c None.
98+
static Optional<FunctionArgApplyInfo>
99+
getFunctionArgApplyInfo(ConstraintSystem &cs, ConstraintLocator *locator);
100+
94101
/// Resolve type variables present in the raw type, if any.
95102
Type resolveType(Type rawType, bool reconstituteSugar = false,
96103
bool wantRValue = true) const {
@@ -113,10 +120,6 @@ class FailureDiagnostic {
113120
});
114121
}
115122

116-
/// Resolve type variables present in the raw type, using generic parameter
117-
/// types where possible.
118-
Type resolveInterfaceType(Type type, bool reconstituteSugar = false) const;
119-
120123
template <typename... ArgTypes>
121124
InFlightDiagnostic emitDiagnostic(ArgTypes &&... Args) const;
122125

@@ -176,13 +179,6 @@ class FailureDiagnostic {
176179
/// of a given locator's anchor, or \c None if no such choice can be found.
177180
Optional<SelectedOverload> getChoiceFor(ConstraintLocator *) const;
178181

179-
/// For a given locator describing a function argument conversion, or a
180-
/// constraint within an argument conversion, returns information about the
181-
/// application of the argument to its parameter. If the locator is not
182-
/// for an argument conversion, returns \c None.
183-
Optional<FunctionArgApplyInfo>
184-
getFunctionArgApplyInfo(ConstraintLocator *locator) const;
185-
186182
/// \returns A new type with all of the type variables associated with
187183
/// generic parameters substituted back into being generic parameter type.
188184
Type restoreGenericParameters(
@@ -978,16 +974,17 @@ class InvalidUseOfAddressOf final : public ContextualFailure {
978974
/// Diagnose mismatches relating to tuple destructuring.
979975
class TupleContextualFailure final : public ContextualFailure {
980976
public:
981-
TupleContextualFailure(ConstraintSystem &cs, Type lhs, Type rhs,
982-
ConstraintLocator *locator)
983-
: ContextualFailure(cs, lhs, rhs, locator) {}
977+
TupleContextualFailure(ConstraintSystem &cs, ContextualTypePurpose purpose,
978+
Type lhs, Type rhs, ConstraintLocator *locator)
979+
: ContextualFailure(cs, purpose, lhs, rhs, locator) {
980+
assert(getFromType()->is<TupleType>() && getToType()->is<TupleType>());
981+
}
984982

985983
bool diagnoseAsError() override;
986984

987985
bool isNumElementsMismatch() const {
988986
auto lhsTy = getFromType()->castTo<TupleType>();
989987
auto rhsTy = getToType()->castTo<TupleType>();
990-
assert(lhsTy && rhsTy);
991988
return lhsTy->getNumElements() != rhsTy->getNumElements();
992989
}
993990
};
@@ -1819,7 +1816,7 @@ class ArgumentMismatchFailure : public ContextualFailure {
18191816
ArgumentMismatchFailure(ConstraintSystem &cs, Type argType,
18201817
Type paramType, ConstraintLocator *locator)
18211818
: ContextualFailure(cs, argType, paramType, locator),
1822-
Info(getFunctionArgApplyInfo(getLocator())) {}
1819+
Info(getFunctionArgApplyInfo(cs, getLocator())) {}
18231820

18241821
bool diagnoseAsError() override;
18251822
bool diagnoseAsNote() override;

lib/Sema/CSFix.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,17 +255,51 @@ ContextualMismatch *ContextualMismatch::create(ConstraintSystem &cs, Type lhs,
255255
return new (cs.getAllocator()) ContextualMismatch(cs, lhs, rhs, locator);
256256
}
257257

258-
bool AllowTupleTypeMismatch::diagnose(bool asNote) const {
259-
auto failure = TupleContextualFailure(
260-
getConstraintSystem(), getFromType(), getToType(), getLocator());
258+
bool AllowTupleTypeMismatch::coalesceAndDiagnose(
259+
ArrayRef<ConstraintFix *> fixes, bool asNote) const {
260+
auto &cs = getConstraintSystem();
261+
auto *locator = getLocator();
262+
auto purpose = cs.getContextualTypePurpose();
263+
Type fromType;
264+
Type toType;
265+
266+
if (getFromType()->is<TupleType>() && getToType()->is<TupleType>()) {
267+
fromType = getFromType();
268+
toType = getToType();
269+
} else if (auto contextualType = cs.getContextualType()) {
270+
auto *tupleExpr = simplifyLocatorToAnchor(locator);
271+
if (!tupleExpr)
272+
return false;
273+
fromType = cs.getType(tupleExpr);
274+
toType = contextualType;
275+
} else if (auto argApplyInfo =
276+
FailureDiagnostic::getFunctionArgApplyInfo(cs, locator)) {
277+
purpose = CTP_CallArgument;
278+
fromType = argApplyInfo->getArgType();
279+
toType = argApplyInfo->getParamType();
280+
} else if (auto *coerceExpr = dyn_cast<CoerceExpr>(locator->getAnchor())) {
281+
purpose = CTP_CoerceOperand;
282+
fromType = cs.getType(coerceExpr->getSubExpr());
283+
toType = cs.getType(coerceExpr);
284+
} else if (auto *assignExpr = dyn_cast<AssignExpr>(locator->getAnchor())) {
285+
purpose = CTP_AssignSource;
286+
fromType = cs.getType(assignExpr->getSrc());
287+
toType = cs.getType(assignExpr->getDest());
288+
} else {
289+
return false;
290+
}
291+
292+
TupleContextualFailure failure(cs, purpose, fromType, toType, locator);
261293
return failure.diagnose(asNote);
262294
}
263295

296+
bool AllowTupleTypeMismatch::diagnose(bool asNote) const {
297+
return coalesceAndDiagnose({}, asNote);
298+
}
299+
264300
AllowTupleTypeMismatch *
265301
AllowTupleTypeMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs,
266302
ConstraintLocator *locator) {
267-
assert(lhs->is<TupleType>() && rhs->is<TupleType>() &&
268-
"lhs and rhs must be tuple types");
269303
return new (cs.getAllocator()) AllowTupleTypeMismatch(cs, lhs, rhs, locator);
270304
}
271305

lib/Sema/CSFix.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,10 +963,17 @@ class AllowTupleTypeMismatch final : public ContextualMismatch {
963963
static AllowTupleTypeMismatch *create(ConstraintSystem &cs, Type lhs,
964964
Type rhs, ConstraintLocator *locator);
965965

966+
static bool classof(const ConstraintFix *fix) {
967+
return fix->getKind() == FixKind::AllowTupleTypeMismatch;
968+
}
969+
966970
std::string getName() const override {
967971
return "fix tuple mismatches in type and arity";
968972
}
969973

974+
bool coalesceAndDiagnose(ArrayRef<ConstraintFix *> secondaryFixes,
975+
bool asNote = false) const override;
976+
970977
bool diagnose(bool asNote = false) const override;
971978
};
972979

0 commit comments

Comments
 (0)