Skip to content

Commit ee315ec

Browse files
authored
Merge pull request swiftlang#37066 from xedin/rdar-68795727-5.5
[5.5][Diagnostics] Avoid relying on solution for contextual purpose information
2 parents 71a4b63 + 458fae7 commit ee315ec

File tree

12 files changed

+140
-85
lines changed

12 files changed

+140
-85
lines changed

include/swift/Sema/ConstraintLocator.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,46 @@ class Pattern;
4141
class SourceManager;
4242
class ProtocolConformance;
4343

44+
/// This specifies the purpose of the contextual type, when specified to
45+
/// typeCheckExpression. This is used for diagnostic generation to produce more
46+
/// specified error messages when the conversion fails.
47+
///
48+
enum ContextualTypePurpose : uint8_t {
49+
CTP_Unused, ///< No contextual type is specified.
50+
CTP_Initialization, ///< Pattern binding initialization.
51+
CTP_ReturnStmt, ///< Value specified to a 'return' statement.
52+
CTP_ReturnSingleExpr, ///< Value implicitly returned from a function.
53+
CTP_YieldByValue, ///< By-value yield operand.
54+
CTP_YieldByReference, ///< By-reference yield operand.
55+
CTP_ThrowStmt, ///< Value specified to a 'throw' statement.
56+
CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
57+
CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.
58+
59+
/// Default value in @autoclosure parameter
60+
/// 'foo(a : @autoclosure () -> Int = 42)'.
61+
CTP_AutoclosureDefaultParameter,
62+
63+
CTP_CalleeResult, ///< Constraint is placed on the result of a callee.
64+
CTP_CallArgument, ///< Call to function or operator requires type.
65+
CTP_ClosureResult, ///< Closure result expects a specific type.
66+
CTP_ArrayElement, ///< ArrayExpr wants elements to have a specific type.
67+
CTP_DictionaryKey, ///< DictionaryExpr keys should have a specific type.
68+
CTP_DictionaryValue, ///< DictionaryExpr values should have a specific type.
69+
CTP_CoerceOperand, ///< CoerceExpr operand coerced to specific type.
70+
CTP_AssignSource, ///< AssignExpr source operand coerced to result type.
71+
CTP_SubscriptAssignSource, ///< AssignExpr source operand coerced to subscript
72+
///< result type.
73+
CTP_Condition, ///< Condition expression of various statements e.g.
74+
///< `if`, `for`, `while` etc.
75+
CTP_ForEachStmt, ///< "expression/sequence" associated with 'for-in' loop
76+
///< is expected to conform to 'Sequence' protocol.
77+
CTP_WrappedProperty, ///< Property type expected to match 'wrappedValue' type
78+
CTP_ComposedPropertyWrapper, ///< Composed wrapper type expected to match
79+
///< former 'wrappedValue' type
80+
81+
CTP_CannotFail, ///< Conversion can never fail. abort() if it does.
82+
};
83+
4484
namespace constraints {
4585

4686
class ConstraintSystem;
@@ -826,6 +866,25 @@ class LocatorPathElt::ImplicitConversion final
826866
}
827867
};
828868

869+
class LocatorPathElt::ContextualType final : public StoredIntegerElement<1> {
870+
public:
871+
ContextualType(ContextualTypePurpose purpose)
872+
: StoredIntegerElement(ConstraintLocator::ContextualType,
873+
static_cast<unsigned>(purpose)) {}
874+
875+
ContextualTypePurpose getPurpose() const {
876+
return static_cast<ContextualTypePurpose>(getValue());
877+
}
878+
879+
bool isFor(ContextualTypePurpose purpose) const {
880+
return getPurpose() == purpose;
881+
}
882+
883+
static bool classof(const LocatorPathElt *elt) {
884+
return elt->getKind() == ConstraintLocator::ContextualType;
885+
}
886+
};
887+
829888
namespace details {
830889
template <typename CustomPathElement>
831890
class PathElement {

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ CUSTOM_LOCATOR_PATH_ELT(ClosureBody)
6161
SIMPLE_LOCATOR_PATH_ELT(ConstructorMember)
6262

6363
/// The desired contextual type passed in to the constraint system.
64-
SIMPLE_LOCATOR_PATH_ELT(ContextualType)
64+
CUSTOM_LOCATOR_PATH_ELT(ContextualType)
6565

6666
/// A result of an expression involving dynamic lookup.
6767
SIMPLE_LOCATOR_PATH_ELT(DynamicLookupResult)

include/swift/Sema/ConstraintSystem.h

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -90,46 +90,6 @@ void *operator new(size_t bytes, swift::constraints::ConstraintSystem& cs,
9090

9191
namespace swift {
9292

93-
/// This specifies the purpose of the contextual type, when specified to
94-
/// typeCheckExpression. This is used for diagnostic generation to produce more
95-
/// specified error messages when the conversion fails.
96-
///
97-
enum ContextualTypePurpose {
98-
CTP_Unused, ///< No contextual type is specified.
99-
CTP_Initialization, ///< Pattern binding initialization.
100-
CTP_ReturnStmt, ///< Value specified to a 'return' statement.
101-
CTP_ReturnSingleExpr, ///< Value implicitly returned from a function.
102-
CTP_YieldByValue, ///< By-value yield operand.
103-
CTP_YieldByReference, ///< By-reference yield operand.
104-
CTP_ThrowStmt, ///< Value specified to a 'throw' statement.
105-
CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
106-
CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.
107-
108-
/// Default value in @autoclosure parameter
109-
/// 'foo(a : @autoclosure () -> Int = 42)'.
110-
CTP_AutoclosureDefaultParameter,
111-
112-
CTP_CalleeResult, ///< Constraint is placed on the result of a callee.
113-
CTP_CallArgument, ///< Call to function or operator requires type.
114-
CTP_ClosureResult, ///< Closure result expects a specific type.
115-
CTP_ArrayElement, ///< ArrayExpr wants elements to have a specific type.
116-
CTP_DictionaryKey, ///< DictionaryExpr keys should have a specific type.
117-
CTP_DictionaryValue, ///< DictionaryExpr values should have a specific type.
118-
CTP_CoerceOperand, ///< CoerceExpr operand coerced to specific type.
119-
CTP_AssignSource, ///< AssignExpr source operand coerced to result type.
120-
CTP_SubscriptAssignSource, ///< AssignExpr source operand coerced to subscript
121-
///< result type.
122-
CTP_Condition, ///< Condition expression of various statements e.g.
123-
///< `if`, `for`, `while` etc.
124-
CTP_ForEachStmt, ///< "expression/sequence" associated with 'for-in' loop
125-
///< is expected to conform to 'Sequence' protocol.
126-
CTP_WrappedProperty, ///< Property type expected to match 'wrappedValue' type
127-
CTP_ComposedPropertyWrapper, ///< Composed wrapper type expected to match
128-
///< former 'wrappedValue' type
129-
130-
CTP_CannotFail, ///< Conversion can never fail. abort() if it does.
131-
};
132-
13393
/// Specify how we handle the binding of underconstrained (free) type variables
13494
/// within a solution to a constraint system.
13595
enum class FreeTypeVariableBinding {

lib/Sema/BuilderTransform.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ class BuilderClosureVisitor
767767
// If needed, generate constraints for everything in the case statement.
768768
if (cs) {
769769
auto locator = cs->getConstraintLocator(
770-
subjectExpr, LocatorPathElt::ContextualType());
770+
subjectExpr, LocatorPathElt::ContextualType(CTP_Initialization));
771771
Type subjectType = cs->getType(subjectExpr);
772772

773773
if (cs->generateConstraints(caseStmt, dc, subjectType, locator)) {
@@ -851,7 +851,7 @@ class BuilderClosureVisitor
851851
cs->addConstraint(
852852
ConstraintKind::Equal, cs->getType(arrayInitExpr), arrayType,
853853
cs->getConstraintLocator(
854-
arrayInitExpr, LocatorPathElt::ContextualType()));
854+
arrayInitExpr, LocatorPathElt::ContextualType(CTP_Initialization)));
855855

856856
// Form a call to Array.append(_:) to add the result of executing each
857857
// iteration of the loop body to the array formed above.

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8343,8 +8343,8 @@ static Optional<SolutionApplicationTarget> applySolutionToInitialization(
83438343

83448344
// Convert the initializer to the type of the pattern.
83458345
auto &cs = solution.getConstraintSystem();
8346-
auto locator =
8347-
cs.getConstraintLocator(initializer, LocatorPathElt::ContextualType());
8346+
auto locator = cs.getConstraintLocator(
8347+
initializer, LocatorPathElt::ContextualType(CTP_Initialization));
83488348
initializer = solution.coerceToType(initializer, initType, locator);
83498349
if (!initializer)
83508350
return None;

lib/Sema/CSDiagnostics.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2442,8 +2442,9 @@ bool ContextualFailure::diagnoseConversionToNil() const {
24422442

24432443
Optional<ContextualTypePurpose> CTP;
24442444
// Easy case were failure has been identified as contextual already.
2445-
if (locator->isLastElement<LocatorPathElt::ContextualType>()) {
2446-
CTP = getContextualTypePurpose();
2445+
if (auto contextualTy =
2446+
locator->getLastElementAs<LocatorPathElt::ContextualType>()) {
2447+
CTP = contextualTy->getPurpose();
24472448
} else {
24482449
// Here we need to figure out where where `nil` is located.
24492450
// It could be e.g. an argument to a subscript/call, assignment
@@ -6691,8 +6692,9 @@ bool UnableToInferClosureParameterType::diagnoseAsError() {
66916692

66926693
// If there is a contextual mismatch associated with this
66936694
// closure, let's not diagnose any parameter type issues.
6694-
if (hasFixFor(solution, getConstraintLocator(
6695-
closure, LocatorPathElt::ContextualType())))
6695+
if (hasFixFor(solution,
6696+
getConstraintLocator(closure, LocatorPathElt::ContextualType(
6697+
CTP_Initialization))))
66966698
return false;
66976699

66986700
if (auto *parentExpr = findParentExpr(closure)) {

lib/Sema/CSDiagnostics.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -594,8 +594,11 @@ class ContextualFailure : public FailureDiagnostic {
594594
ConstraintLocator *locator)
595595
: ContextualFailure(
596596
solution,
597-
solution.getConstraintSystem().getContextualTypePurpose(
598-
locator->getAnchor()),
597+
locator->isForContextualType()
598+
? locator->castLastElementTo<LocatorPathElt::ContextualType>()
599+
.getPurpose()
600+
: solution.getConstraintSystem().getContextualTypePurpose(
601+
locator->getAnchor()),
599602
lhs, rhs, locator) {}
600603

601604
ContextualFailure(const Solution &solution, ContextualTypePurpose purpose,

lib/Sema/CSFix.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,15 +379,16 @@ ContextualMismatch *ContextualMismatch::create(ConstraintSystem &cs, Type lhs,
379379
/// and the contextual type.
380380
static Optional<std::tuple<ContextualTypePurpose, Type, Type>>
381381
getStructuralTypeContext(const Solution &solution, ConstraintLocator *locator) {
382-
if (locator->findLast<LocatorPathElt::ContextualType>()) {
382+
if (auto contextualTypeElt =
383+
locator->findLast<LocatorPathElt::ContextualType>()) {
383384
assert(locator->isLastElement<LocatorPathElt::ContextualType>() ||
384385
locator->isLastElement<LocatorPathElt::FunctionArgument>());
385386

386387
auto &cs = solution.getConstraintSystem();
387388
auto anchor = locator->getAnchor();
388389
auto contextualType = cs.getContextualType(anchor);
389390
auto exprType = cs.getType(anchor);
390-
return std::make_tuple(cs.getContextualTypePurpose(anchor), exprType,
391+
return std::make_tuple(contextualTypeElt->getPurpose(), exprType,
391392
contextualType);
392393
} else if (auto argApplyInfo = solution.getFunctionArgApplyInfo(locator)) {
393394
return std::make_tuple(CTP_CallArgument,
@@ -1328,7 +1329,8 @@ bool IgnoreAssignmentDestinationType::diagnose(const Solution &solution,
13281329

13291330
AssignmentTypeMismatchFailure failure(
13301331
solution, CTP, getFromType(), getToType(),
1331-
cs.getConstraintLocator(AE->getSrc(), LocatorPathElt::ContextualType()));
1332+
cs.getConstraintLocator(AE->getSrc(),
1333+
LocatorPathElt::ContextualType(CTP)));
13321334
return failure.diagnose(asNote);
13331335
}
13341336

lib/Sema/CSGen.cpp

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3612,8 +3612,10 @@ static bool generateWrappedPropertyTypeConstraints(
36123612
cs.addConstraint(ConstraintKind::Equal, wrapperType, initializerType, locator);
36133613
} else {
36143614
// The former wrappedValue type must be equal to the current wrapper type
3615-
cs.addConstraint(ConstraintKind::Equal, wrapperType, wrappedValueType,
3616-
cs.getConstraintLocator(locator, LocatorPathElt::ContextualType()));
3615+
cs.addConstraint(
3616+
ConstraintKind::Equal, wrapperType, wrappedValueType,
3617+
cs.getConstraintLocator(locator, LocatorPathElt::ContextualType(
3618+
CTP_ComposedPropertyWrapper)));
36173619
cs.setContextualType(typeExpr, TypeLoc::withoutLoc(wrappedValueType),
36183620
CTP_ComposedPropertyWrapper);
36193621
}
@@ -3623,8 +3625,10 @@ static bool generateWrappedPropertyTypeConstraints(
36233625
}
36243626

36253627
// The property type must be equal to the wrapped value type
3626-
cs.addConstraint(ConstraintKind::Equal, propertyType, wrappedValueType,
3627-
cs.getConstraintLocator(wrappedVar, LocatorPathElt::ContextualType()));
3628+
cs.addConstraint(
3629+
ConstraintKind::Equal, propertyType, wrappedValueType,
3630+
cs.getConstraintLocator(
3631+
wrappedVar, LocatorPathElt::ContextualType(CTP_WrappedProperty)));
36283632
cs.setContextualType(wrappedVar, TypeLoc::withoutLoc(wrappedValueType),
36293633
CTP_WrappedProperty);
36303634
return false;
@@ -3634,8 +3638,8 @@ static bool generateWrappedPropertyTypeConstraints(
36343638
static bool generateInitPatternConstraints(
36353639
ConstraintSystem &cs, SolutionApplicationTarget target, Expr *initializer) {
36363640
auto pattern = target.getInitializationPattern();
3637-
auto locator =
3638-
cs.getConstraintLocator(initializer, LocatorPathElt::ContextualType());
3641+
auto locator = cs.getConstraintLocator(
3642+
initializer, LocatorPathElt::ContextualType(CTP_Initialization));
36393643
Type patternType = cs.generateConstraints(
36403644
pattern, locator, target.shouldBindPatternVarsOneWay(),
36413645
target.getInitializationPatternBindingDecl(),
@@ -3666,8 +3670,8 @@ generateForEachStmtConstraints(
36663670
bool isAsync = stmt->getAwaitLoc().isValid();
36673671

36683672
auto locator = cs.getConstraintLocator(sequence);
3669-
auto contextualLocator =
3670-
cs.getConstraintLocator(sequence, LocatorPathElt::ContextualType());
3673+
auto contextualLocator = cs.getConstraintLocator(
3674+
sequence, LocatorPathElt::ContextualType(CTP_ForEachStmt));
36713675

36723676
// The expression type must conform to the Sequence protocol.
36733677
auto sequenceProto = TypeChecker::getProtocol(
@@ -3784,8 +3788,9 @@ bool ConstraintSystem::generateConstraints(
37843788
if (target.isOptionalSomePatternInit()) {
37853789
assert(!target.getExprContextualType() &&
37863790
"some pattern cannot have contextual type pre-configured");
3787-
auto *convertTypeLocator =
3788-
getConstraintLocator(expr, LocatorPathElt::ContextualType());
3791+
auto *convertTypeLocator = getConstraintLocator(
3792+
expr, LocatorPathElt::ContextualType(
3793+
target.getExprContextualTypePurpose()));
37893794
Type var = createTypeVariable(convertTypeLocator, TVO_CanBindToNoEscape);
37903795
target.setExprConversionType(TypeChecker::getOptionalType(expr->getLoc(), var));
37913796
}
@@ -3807,7 +3812,7 @@ bool ConstraintSystem::generateConstraints(
38073812
ContextualTypePurpose ctp = target.getExprContextualTypePurpose();
38083813
bool isOpaqueReturnType = target.infersOpaqueReturnType();
38093814
auto *convertTypeLocator =
3810-
getConstraintLocator(expr, LocatorPathElt::ContextualType());
3815+
getConstraintLocator(expr, LocatorPathElt::ContextualType(ctp));
38113816

38123817
auto getLocator = [&](Type ty) -> ConstraintLocator * {
38133818
// If we have a placeholder originating from a PlaceholderTypeRepr,
@@ -3970,11 +3975,10 @@ bool ConstraintSystem::generateConstraints(StmtCondition condition,
39703975
return true;
39713976
}
39723977

3973-
addConstraint(ConstraintKind::Conversion,
3974-
getType(condExpr),
3975-
boolTy,
3976-
getConstraintLocator(condExpr,
3977-
LocatorPathElt::ContextualType()));
3978+
addConstraint(
3979+
ConstraintKind::Conversion, getType(condExpr), boolTy,
3980+
getConstraintLocator(condExpr,
3981+
LocatorPathElt::ContextualType(CTP_Condition)));
39783982
continue;
39793983
}
39803984

lib/Sema/CSSimplify.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4778,14 +4778,14 @@ bool ConstraintSystem::repairFailures(
47784778
// truth and produce a contextual mismatch instead of per-branch failure,
47794779
// because it's a better pointer than potential then-to-else type mismatch.
47804780
if (auto contextualType = getContextualType(anchor)) {
4781+
auto purpose = getContextualTypePurpose(anchor);
47814782
if (contextualType->isEqual(rhs)) {
4782-
auto *loc =
4783-
getConstraintLocator(anchor, LocatorPathElt::ContextualType());
4783+
auto *loc = getConstraintLocator(
4784+
anchor, LocatorPathElt::ContextualType(purpose));
47844785
if (hasFixFor(loc, FixKind::ContextualMismatch))
47854786
return true;
47864787

4787-
if (contextualType->isVoid() &&
4788-
getContextualTypePurpose(anchor) == CTP_ReturnStmt) {
4788+
if (contextualType->isVoid() && purpose == CTP_ReturnStmt) {
47894789
conversionsOrFixes.push_back(RemoveReturn::create(*this, lhs, loc));
47904790
break;
47914791
}
@@ -5749,12 +5749,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
57495749
}
57505750

57515751
// Single expression function with implicit `return`.
5752-
if (elt->is<LocatorPathElt::ContextualType>()) {
5753-
auto anchor = locator.getAnchor();
5754-
auto contextualInfo = getContextualTypeInfo(anchor);
5755-
assert(contextualInfo &&
5756-
"Found contextual type locator without additional information");
5757-
if (contextualInfo->purpose == CTP_ReturnSingleExpr) {
5752+
if (auto contextualType = elt->getAs<LocatorPathElt::ContextualType>()) {
5753+
if (contextualType->isFor(CTP_ReturnSingleExpr)) {
57585754
increaseScore(SK_FunctionConversion);
57595755
return getTypeMatchSuccess();
57605756
}
@@ -6130,7 +6126,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
61306126
if (auto *Nil = getAsExpr<NilLiteralExpr>(anchor)) {
61316127
auto *fixLocator = getConstraintLocator(
61326128
getContextualType(Nil)
6133-
? locator.withPathElement(LocatorPathElt::ContextualType())
6129+
? locator.withPathElement(LocatorPathElt::ContextualType(
6130+
getContextualTypePurpose(Nil)))
61346131
: locator);
61356132

61366133
// Here the roles are reversed - `nil` is something we are trying to
@@ -11786,7 +11783,7 @@ void ConstraintSystem::addContextualConversionConstraint(
1178611783

1178711784
// Add the constraint.
1178811785
auto *convertTypeLocator =
11789-
getConstraintLocator(expr, LocatorPathElt::ContextualType());
11786+
getConstraintLocator(expr, LocatorPathElt::ContextualType(purpose));
1179011787
addConstraint(constraintKind, getType(expr), conversionType,
1179111788
convertTypeLocator, /*isFavored*/ true);
1179211789
}

0 commit comments

Comments
 (0)