Skip to content

Commit edb4e70

Browse files
authored
Merge pull request #28600 from hborla/tuple-mismatch-diagnostics
[ConstraintSystem] Port tuple type mismatch diagnostics
2 parents 7c46df6 + 94e9fd1 commit edb4e70

17 files changed

+448
-403
lines changed

docs/TypeChecker.rst

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -981,9 +981,6 @@ to the new diagnostic framework, which is described in detail in this
981981

982982
The things in the queue yet to be ported are:
983983

984-
- ``visitTupleExpr``: Diagnostics related to label/type mismatches
985-
associated with tuple conversions.
986-
987984
- Diagnostics related to member references: ``diagnoseMemberFailures``.
988985
Most of the associated diagnostics have been ported and fixes are
989986
located in ``ConstraintSystem::simplifyMemberConstraint``.

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -955,9 +955,8 @@ ERROR(types_not_convertible_use_bool_value,none,
955955
ERROR(tuple_types_not_convertible_nelts,none,
956956
"%0 is not convertible to %1, "
957957
"tuples have a different number of elements", (Type, Type))
958-
959958
ERROR(tuple_types_not_convertible,none,
960-
"tuple type %0 is not convertible to tuple %1", (Type, Type))
959+
"tuple type %0 is not convertible to tuple type %1", (Type, Type))
961960

962961
ERROR(invalid_force_unwrap,none,
963962
"cannot force unwrap value of non-optional type %0", (Type))

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);
@@ -2909,58 +2908,6 @@ bool FailureDiagnosis::visitUnresolvedDotExpr(UnresolvedDotExpr *UDE) {
29092908
locator);
29102909
}
29112910

2912-
/// A TupleExpr propagate contextual type information down to its children and
2913-
/// can be erroneous when there is a label mismatch etc.
2914-
bool FailureDiagnosis::visitTupleExpr(TupleExpr *TE) {
2915-
// If we know the requested argType to use, use computeTupleShuffle to produce
2916-
// the shuffle of input arguments to destination values. It requires a
2917-
// TupleType to compute the mapping from argExpr. Conveniently, it doesn't
2918-
// care about the actual types though, so we can just use 'void' for them.
2919-
if (!CS.getContextualType() || !CS.getContextualType()->is<TupleType>())
2920-
return visitExpr(TE);
2921-
2922-
auto contextualTT = CS.getContextualType()->castTo<TupleType>();
2923-
2924-
SmallVector<TupleTypeElt, 4> ArgElts;
2925-
auto voidTy = CS.getASTContext().TheEmptyTupleType;
2926-
2927-
for (unsigned i = 0, e = TE->getNumElements(); i != e; ++i)
2928-
ArgElts.push_back({ voidTy, TE->getElementName(i) });
2929-
auto TEType = TupleType::get(ArgElts, CS.getASTContext());
2930-
2931-
if (!TEType->is<TupleType>())
2932-
return visitExpr(TE);
2933-
2934-
SmallVector<unsigned, 4> sources;
2935-
2936-
// If the shuffle is invalid, then there is a type error. We could diagnose
2937-
// it specifically here, but the general logic does a fine job so we let it
2938-
// do it.
2939-
if (computeTupleShuffle(TEType->castTo<TupleType>()->getElements(),
2940-
contextualTT->getElements(), sources))
2941-
return visitExpr(TE);
2942-
2943-
// If we got a correct shuffle, we can perform the analysis of all of
2944-
// the input elements, with their expected types.
2945-
for (unsigned i = 0, e = sources.size(); i != e; ++i) {
2946-
// Otherwise, it must match the corresponding expected argument type.
2947-
unsigned inArgNo = sources[i];
2948-
2949-
TCCOptions options;
2950-
if (contextualTT->getElement(i).isInOut())
2951-
options |= TCC_AllowLValue;
2952-
2953-
auto actualType = contextualTT->getElementType(i);
2954-
auto exprResult =
2955-
typeCheckChildIndependently(TE->getElement(inArgNo), actualType,
2956-
CS.getContextualTypePurpose(), options);
2957-
// If there was an error type checking this argument, then we're done.
2958-
if (!exprResult) return true;
2959-
}
2960-
2961-
return false;
2962-
}
2963-
29642911
/// An IdentityExpr doesn't change its argument, but it *can* propagate its
29652912
/// contextual type information down.
29662913
bool FailureDiagnosis::visitIdentityExpr(IdentityExpr *E) {

lib/Sema/CSDiagnostics.cpp

Lines changed: 23 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -137,165 +137,6 @@ FailureDiagnostic::getChoiceFor(ConstraintLocator *locator) const {
137137
return getOverloadChoiceIfAvailable(cs.getCalleeLocator(locator));
138138
}
139139

140-
Type FailureDiagnostic::resolveInterfaceType(Type type,
141-
bool reconstituteSugar) const {
142-
auto &cs = getConstraintSystem();
143-
auto resolvedType = type.transform([&](Type type) -> Type {
144-
if (auto *tvt = type->getAs<TypeVariableType>()) {
145-
// If this type variable is for a generic parameter, return that.
146-
if (auto *gp = tvt->getImpl().getGenericParameter())
147-
return gp;
148-
149-
// Otherwise resolve its fixed type, mapped out of context.
150-
if (auto fixed = cs.getFixedType(tvt))
151-
return resolveInterfaceType(fixed->mapTypeOutOfContext());
152-
153-
return cs.getRepresentative(tvt);
154-
}
155-
if (auto *dmt = type->getAs<DependentMemberType>()) {
156-
// For a dependent member, first resolve the base.
157-
auto newBase = resolveInterfaceType(dmt->getBase());
158-
159-
// Then reconstruct using its associated type.
160-
assert(dmt->getAssocType());
161-
return DependentMemberType::get(newBase, dmt->getAssocType());
162-
}
163-
return type;
164-
});
165-
166-
assert(!resolvedType->hasArchetype());
167-
return reconstituteSugar ? resolvedType->reconstituteSugar(/*recursive*/ true)
168-
: resolvedType;
169-
}
170-
171-
/// Given an apply expr, returns true if it is expected to have a direct callee
172-
/// overload, resolvable using `getChoiceFor`. Otherwise, returns false.
173-
static bool shouldHaveDirectCalleeOverload(const CallExpr *callExpr) {
174-
auto *fnExpr = callExpr->getDirectCallee();
175-
176-
// An apply of an apply/subscript doesn't have a direct callee.
177-
if (isa<ApplyExpr>(fnExpr) || isa<SubscriptExpr>(fnExpr))
178-
return false;
179-
180-
// Applies of closures don't have callee overloads.
181-
if (isa<ClosureExpr>(fnExpr))
182-
return false;
183-
184-
// No direct callee for a try!/try?.
185-
if (isa<ForceTryExpr>(fnExpr) || isa<OptionalTryExpr>(fnExpr))
186-
return false;
187-
188-
// If we have an intermediate cast, there's no direct callee.
189-
if (isa<ExplicitCastExpr>(fnExpr))
190-
return false;
191-
192-
// No direct callee for an if expr.
193-
if (isa<IfExpr>(fnExpr))
194-
return false;
195-
196-
// Assume that anything else would have a direct callee.
197-
return true;
198-
}
199-
200-
Optional<FunctionArgApplyInfo>
201-
FailureDiagnostic::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
202-
auto &cs = getConstraintSystem();
203-
auto *anchor = locator->getAnchor();
204-
auto path = locator->getPath();
205-
206-
// Look for the apply-arg-to-param element in the locator's path. We may
207-
// have to look through other elements that are generated from an argument
208-
// conversion such as GenericArgument for an optional-to-optional conversion,
209-
// and OptionalPayload for a value-to-optional conversion.
210-
auto iter = path.rbegin();
211-
auto applyArgElt = locator->findLast<LocatorPathElt::ApplyArgToParam>(iter);
212-
if (!applyArgElt)
213-
return None;
214-
215-
auto nextIter = iter + 1;
216-
assert(!locator->findLast<LocatorPathElt::ApplyArgToParam>(nextIter) &&
217-
"Multiple ApplyArgToParam components?");
218-
219-
// Form a new locator that ends at the apply-arg-to-param element, and
220-
// simplify it to get the full argument expression.
221-
auto argPath = path.drop_back(iter - path.rbegin());
222-
auto *argLocator = cs.getConstraintLocator(
223-
anchor, argPath, ConstraintLocator::getSummaryFlagsForPath(argPath));
224-
225-
auto *argExpr = simplifyLocatorToAnchor(argLocator);
226-
227-
// If we were unable to simplify down to the argument expression, we don't
228-
// know what this is.
229-
if (!argExpr)
230-
return None;
231-
232-
Optional<OverloadChoice> choice;
233-
Type rawFnType;
234-
if (auto overload = getChoiceFor(argLocator)) {
235-
// If we have resolved an overload for the callee, then use that to get the
236-
// function type and callee.
237-
choice = overload->choice;
238-
rawFnType = overload->openedType;
239-
} else {
240-
// If we didn't resolve an overload for the callee, we should be dealing
241-
// with a call of an arbitrary function expr.
242-
if (auto *call = dyn_cast<CallExpr>(anchor)) {
243-
assert(!shouldHaveDirectCalleeOverload(call) &&
244-
"Should we have resolved a callee for this?");
245-
rawFnType = cs.getType(call->getFn());
246-
} else {
247-
// FIXME: ArgumentMismatchFailure is currently used from CSDiag, meaning
248-
// we can end up a BinaryExpr here with an unresolved callee. It should be
249-
// possible to remove this once we've gotten rid of the old CSDiag logic
250-
// and just assert that we have a CallExpr.
251-
auto *apply = cast<ApplyExpr>(anchor);
252-
rawFnType = cs.getType(apply->getFn());
253-
}
254-
}
255-
256-
// Try to resolve the function type by loading lvalues and looking through
257-
// optional types, which can occur for expressions like `fn?(5)`.
258-
auto *fnType = resolveType(rawFnType)
259-
->lookThroughAllOptionalTypes()
260-
->getAs<FunctionType>();
261-
if (!fnType)
262-
return None;
263-
264-
// Resolve the interface type for the function. Note that this may not be a
265-
// function type, for example it could be a generic parameter.
266-
Type fnInterfaceType;
267-
auto *callee = choice ? choice->getDeclOrNull() : nullptr;
268-
if (callee && callee->hasInterfaceType()) {
269-
// If we have a callee with an interface type, we can use it. This is
270-
// preferable to resolveInterfaceType, as this will allow us to get a
271-
// GenericFunctionType for generic decls.
272-
//
273-
// Note that it's possible to find a callee without an interface type. This
274-
// can happen for example with closure parameters, where the interface type
275-
// isn't set until the solution is applied. In that case, use
276-
// resolveInterfaceType.
277-
fnInterfaceType = callee->getInterfaceType();
278-
279-
// Strip off the curried self parameter if necessary.
280-
if (hasAppliedSelf(cs, *choice))
281-
fnInterfaceType = fnInterfaceType->castTo<AnyFunctionType>()->getResult();
282-
283-
if (auto *fn = fnInterfaceType->getAs<AnyFunctionType>()) {
284-
assert(fn->getNumParams() == fnType->getNumParams() &&
285-
"Parameter mismatch?");
286-
(void)fn;
287-
}
288-
} else {
289-
fnInterfaceType = resolveInterfaceType(rawFnType);
290-
}
291-
292-
auto argIdx = applyArgElt->getArgIdx();
293-
auto paramIdx = applyArgElt->getParamIdx();
294-
295-
return FunctionArgApplyInfo(cs, argExpr, argIdx, getType(argExpr),
296-
paramIdx, fnInterfaceType, fnType, callee);
297-
}
298-
299140
Type FailureDiagnostic::restoreGenericParameters(
300141
Type type,
301142
llvm::function_ref<void(GenericTypeParamType *, Type)> substitution) {
@@ -935,7 +776,8 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const {
935776
// Let's check whether this is a function parameter passed
936777
// as an argument to another function which accepts @escaping
937778
// function at that position.
938-
if (auto argApplyInfo = getFunctionArgApplyInfo(getLocator())) {
779+
auto &cs = getConstraintSystem();
780+
if (auto argApplyInfo = cs.getFunctionArgApplyInfo(getLocator())) {
939781
auto paramInterfaceTy = argApplyInfo->getParamInterfaceType();
940782
if (paramInterfaceTy->isTypeParameter()) {
941783
auto diagnoseGenericParamFailure = [&](GenericTypeParamDecl *decl) {
@@ -1143,7 +985,8 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt(
1143985
if (isa<InOutExpr>(anchor))
1144986
return;
1145987

1146-
if (auto argApplyInfo = getFunctionArgApplyInfo(getLocator()))
988+
auto &cs = getConstraintSystem();
989+
if (auto argApplyInfo = cs.getFunctionArgApplyInfo(getLocator()))
1147990
if (argApplyInfo->getParameterFlags().isInOut())
1148991
return;
1149992

@@ -2967,9 +2810,18 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
29672810
}
29682811

29692812
bool TupleContextualFailure::diagnoseAsError() {
2970-
auto diagnostic = isNumElementsMismatch()
2971-
? diag::tuple_types_not_convertible_nelts
2972-
: diag::tuple_types_not_convertible;
2813+
Diag<Type, Type> diagnostic;
2814+
auto purpose = getContextualTypePurpose();
2815+
auto &cs = getConstraintSystem();
2816+
if (isNumElementsMismatch())
2817+
diagnostic = diag::tuple_types_not_convertible_nelts;
2818+
else if ((purpose == CTP_Initialization) && !cs.getContextualType())
2819+
diagnostic = diag::tuple_types_not_convertible;
2820+
else if (auto diag = getDiagnosticFor(purpose, /*forProtocol=*/false))
2821+
diagnostic = *diag;
2822+
else
2823+
return false;
2824+
29732825
emitDiagnostic(getAnchor()->getLoc(), diagnostic, getFromType(), getToType());
29742826
return true;
29752827
}
@@ -3825,7 +3677,7 @@ bool MissingArgumentsFailure::diagnoseAsError() {
38253677
// foo(bar) // `() -> Void` vs. `(Int) -> Void`
38263678
// ```
38273679
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
3828-
auto info = *getFunctionArgApplyInfo(locator);
3680+
auto info = *(cs.getFunctionArgApplyInfo(locator));
38293681

38303682
auto *argExpr = info.getArgExpr();
38313683
emitDiagnostic(argExpr->getLoc(), diag::cannot_convert_argument_value,
@@ -4041,7 +3893,7 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) {
40413893
auto *locator = getLocator();
40423894
if (locator->isForContextualType()) {
40433895
funcType = cs.getContextualType()->getAs<FunctionType>();
4044-
} else if (auto info = getFunctionArgApplyInfo(locator)) {
3896+
} else if (auto info = cs.getFunctionArgApplyInfo(locator)) {
40453897
funcType = info->getParamType()->getAs<FunctionType>();
40463898
} else if (locator->isLastElement<LocatorPathElt::ClosureResult>()) {
40473899
// Based on the locator we know this this is something like this:
@@ -4754,7 +4606,8 @@ SourceLoc InvalidUseOfAddressOf::getLoc() const {
47544606
}
47554607

47564608
bool InvalidUseOfAddressOf::diagnoseAsError() {
4757-
if (auto argApplyInfo = getFunctionArgApplyInfo(getLocator())) {
4609+
auto &cs = getConstraintSystem();
4610+
if (auto argApplyInfo = cs.getFunctionArgApplyInfo(getLocator())) {
47584611
if (!argApplyInfo->getParameterFlags().isInOut()) {
47594612
auto anchor = getAnchor();
47604613
emitDiagnostic(anchor->getLoc(), diag::extra_address_of, getToType())
@@ -5274,18 +5127,19 @@ bool ThrowingFunctionConversionFailure::diagnoseAsError() {
52745127
}
52755128

52765129
bool InOutConversionFailure::diagnoseAsError() {
5130+
auto &cs = getConstraintSystem();
52775131
auto *anchor = getAnchor();
52785132
auto *locator = getLocator();
52795133
auto path = locator->getPath();
52805134

52815135
if (!path.empty() &&
52825136
path.back().getKind() == ConstraintLocator::FunctionArgument) {
5283-
if (auto argApplyInfo = getFunctionArgApplyInfo(locator)) {
5137+
if (auto argApplyInfo = cs.getFunctionArgApplyInfo(locator)) {
52845138
emitDiagnostic(anchor->getLoc(), diag::cannot_convert_argument_value,
52855139
argApplyInfo->getArgType(), argApplyInfo->getParamType());
52865140
} else {
52875141
assert(locator->findLast<LocatorPathElt::ContextualType>());
5288-
auto contextualType = getConstraintSystem().getContextualType();
5142+
auto contextualType = cs.getContextualType();
52895143
auto purpose = getContextualTypePurpose();
52905144
auto diagnostic = getDiagnosticFor(purpose, /*forProtocol=*/false);
52915145

0 commit comments

Comments
 (0)