Skip to content

Commit 820ec90

Browse files
committed
[ConstraintLocator] Augment ContextualType element to carry its purpose
Having purpose attached to the contextual type element makes it much easier to diagnose contextual mismatches without involving constraint system state. (cherry picked from commit 51ff12d)
1 parent d92f389 commit 820ec90

File tree

10 files changed

+95
-71
lines changed

10 files changed

+95
-71
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: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6691,8 +6691,9 @@ bool UnableToInferClosureParameterType::diagnoseAsError() {
66916691

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

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

lib/Sema/CSFix.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1328,7 +1328,8 @@ bool IgnoreAssignmentDestinationType::diagnose(const Solution &solution,
13281328

13291329
AssignmentTypeMismatchFailure failure(
13301330
solution, CTP, getFromType(), getToType(),
1331-
cs.getConstraintLocator(AE->getSrc(), LocatorPathElt::ContextualType()));
1331+
cs.getConstraintLocator(AE->getSrc(),
1332+
LocatorPathElt::ContextualType(CTP)));
13321333
return failure.diagnose(asNote);
13331334
}
13341335

lib/Sema/CSGen.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3623,8 +3623,10 @@ static bool generateWrappedPropertyTypeConstraints(
36233623
}
36243624

36253625
// The property type must be equal to the wrapped value type
3626-
cs.addConstraint(ConstraintKind::Equal, propertyType, wrappedValueType,
3627-
cs.getConstraintLocator(wrappedVar, LocatorPathElt::ContextualType()));
3626+
cs.addConstraint(
3627+
ConstraintKind::Equal, propertyType, wrappedValueType,
3628+
cs.getConstraintLocator(
3629+
wrappedVar, LocatorPathElt::ContextualType(CTP_WrappedProperty)));
36283630
cs.setContextualType(wrappedVar, TypeLoc::withoutLoc(wrappedValueType),
36293631
CTP_WrappedProperty);
36303632
return false;
@@ -3634,8 +3636,8 @@ static bool generateWrappedPropertyTypeConstraints(
36343636
static bool generateInitPatternConstraints(
36353637
ConstraintSystem &cs, SolutionApplicationTarget target, Expr *initializer) {
36363638
auto pattern = target.getInitializationPattern();
3637-
auto locator =
3638-
cs.getConstraintLocator(initializer, LocatorPathElt::ContextualType());
3639+
auto locator = cs.getConstraintLocator(
3640+
initializer, LocatorPathElt::ContextualType(CTP_Initialization));
36393641
Type patternType = cs.generateConstraints(
36403642
pattern, locator, target.shouldBindPatternVarsOneWay(),
36413643
target.getInitializationPatternBindingDecl(),
@@ -3666,8 +3668,8 @@ generateForEachStmtConstraints(
36663668
bool isAsync = stmt->getAwaitLoc().isValid();
36673669

36683670
auto locator = cs.getConstraintLocator(sequence);
3669-
auto contextualLocator =
3670-
cs.getConstraintLocator(sequence, LocatorPathElt::ContextualType());
3671+
auto contextualLocator = cs.getConstraintLocator(
3672+
sequence, LocatorPathElt::ContextualType(CTP_ForEachStmt));
36713673

36723674
// The expression type must conform to the Sequence protocol.
36733675
auto sequenceProto = TypeChecker::getProtocol(
@@ -3784,8 +3786,9 @@ bool ConstraintSystem::generateConstraints(
37843786
if (target.isOptionalSomePatternInit()) {
37853787
assert(!target.getExprContextualType() &&
37863788
"some pattern cannot have contextual type pre-configured");
3787-
auto *convertTypeLocator =
3788-
getConstraintLocator(expr, LocatorPathElt::ContextualType());
3789+
auto *convertTypeLocator = getConstraintLocator(
3790+
expr, LocatorPathElt::ContextualType(
3791+
target.getExprContextualTypePurpose()));
37893792
Type var = createTypeVariable(convertTypeLocator, TVO_CanBindToNoEscape);
37903793
target.setExprConversionType(TypeChecker::getOptionalType(expr->getLoc(), var));
37913794
}
@@ -3807,7 +3810,7 @@ bool ConstraintSystem::generateConstraints(
38073810
ContextualTypePurpose ctp = target.getExprContextualTypePurpose();
38083811
bool isOpaqueReturnType = target.infersOpaqueReturnType();
38093812
auto *convertTypeLocator =
3810-
getConstraintLocator(expr, LocatorPathElt::ContextualType());
3813+
getConstraintLocator(expr, LocatorPathElt::ContextualType(ctp));
38113814

38123815
auto getLocator = [&](Type ty) -> ConstraintLocator * {
38133816
// If we have a placeholder originating from a PlaceholderTypeRepr,
@@ -3970,11 +3973,10 @@ bool ConstraintSystem::generateConstraints(StmtCondition condition,
39703973
return true;
39713974
}
39723975

3973-
addConstraint(ConstraintKind::Conversion,
3974-
getType(condExpr),
3975-
boolTy,
3976-
getConstraintLocator(condExpr,
3977-
LocatorPathElt::ContextualType()));
3976+
addConstraint(
3977+
ConstraintKind::Conversion, getType(condExpr), boolTy,
3978+
getConstraintLocator(condExpr,
3979+
LocatorPathElt::ContextualType(CTP_Condition)));
39783980
continue;
39793981
}
39803982

lib/Sema/CSSimplify.cpp

Lines changed: 7 additions & 6 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
}
@@ -6130,7 +6130,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
61306130
if (auto *Nil = getAsExpr<NilLiteralExpr>(anchor)) {
61316131
auto *fixLocator = getConstraintLocator(
61326132
getContextualType(Nil)
6133-
? locator.withPathElement(LocatorPathElt::ContextualType())
6133+
? locator.withPathElement(LocatorPathElt::ContextualType(
6134+
getContextualTypePurpose(Nil)))
61346135
: locator);
61356136

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

1178711788
// Add the constraint.
1178811789
auto *convertTypeLocator =
11789-
getConstraintLocator(expr, LocatorPathElt::ContextualType());
11790+
getConstraintLocator(expr, LocatorPathElt::ContextualType(purpose));
1179011791
addConstraint(constraintKind, getType(expr), conversionType,
1179111792
convertTypeLocator, /*isFavored*/ true);
1179211793
}

unittests/Sema/BindingInferenceTests.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,9 @@ TEST_F(SemaTest, TestTransitiveProtocolInference) {
187187
auto *typeVar = cs.createTypeVariable(cs.getConstraintLocator({}),
188188
/*options=*/0);
189189

190-
cs.addConstraint(
191-
ConstraintKind::Conversion, typeVar, GPT1,
192-
cs.getConstraintLocator({}, LocatorPathElt::ContextualType()));
190+
cs.addConstraint(ConstraintKind::Conversion, typeVar, GPT1,
191+
cs.getConstraintLocator({}, LocatorPathElt::ContextualType(
192+
CTP_Initialization)));
193193

194194
auto bindings = inferBindings(cs, typeVar);
195195
ASSERT_TRUE(bindings.getConformanceRequirements().empty());

0 commit comments

Comments
 (0)