Skip to content

Commit b6d9dcc

Browse files
authored
Merge pull request #29589 from DougGregor/expr-type-check-flag-cleanups
2 parents 8beb904 + 3190433 commit b6d9dcc

File tree

5 files changed

+80
-44
lines changed

5 files changed

+80
-44
lines changed

lib/Sema/CSDiag.cpp

+2-7
Original file line numberDiff line numberDiff line change
@@ -390,15 +390,10 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
390390
// type check operation.
391391
Expr *preCheckedExpr = subExpr;
392392

393-
// Disable structural checks, because we know that the overall expression
394-
// has type constraint problems, and we don't want to know about any
395-
// syntactic issues in a well-typed subexpression (which might be because
396-
// the context is missing).
397-
TypeCheckExprOptions TCEOptions = TypeCheckExprFlags::DisableStructuralChecks;
398-
399393
// Make sure that typechecker knows that this is an attempt
400394
// to diagnose a problem.
401-
TCEOptions |= TypeCheckExprFlags::SubExpressionDiagnostics;
395+
TypeCheckExprOptions TCEOptions =
396+
TypeCheckExprFlags::SubExpressionDiagnostics;
402397

403398
// Claim that the result is discarded to preserve the lvalue type of
404399
// the expression.

lib/Sema/CSDiagnostics.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
641641
switch (last.getKind()) {
642642
case ConstraintLocator::ContextualType: {
643643
auto purpose = getContextualTypePurpose();
644-
assert(!(purpose == CTP_Unused && purpose == CTP_CannotFail));
644+
assert(!(purpose == CTP_Unused || purpose == CTP_CannotFail));
645645

646646
// If this is call to a closure e.g. `let _: A = { B() }()`
647647
// let's point diagnostic to its result.

lib/Sema/ConstraintSystem.h

+31-4
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ using OpenedTypeMap =
789789

790790
/// Describes contextual type information about a particular expression
791791
/// within a constraint system.
792-
struct ContextualTypeInfo {
792+
struct ContextualTypeInfo {
793793
TypeLoc typeLoc;
794794
ContextualTypePurpose purpose;
795795
bool isOpaqueReturnType = false;
@@ -1149,8 +1149,11 @@ class SolutionApplicationTarget {
11491149
struct {
11501150
Expr *expression;
11511151

1152+
/// The purpose of the contextual type.
1153+
ContextualTypePurpose contextualPurpose;
1154+
11521155
/// The type to which the expression should be converted.
1153-
Type convertType;
1156+
TypeLoc convertType;
11541157

11551158
/// Whether the expression result will be discarded at the end.
11561159
bool isDiscarded;
@@ -1163,9 +1166,18 @@ class SolutionApplicationTarget {
11631166
};
11641167

11651168
public:
1166-
SolutionApplicationTarget(Expr *expr, Type convertType, bool isDiscarded) {
1169+
SolutionApplicationTarget(Expr *expr,
1170+
ContextualTypePurpose contextualPurpose,
1171+
Type convertType, bool isDiscarded)
1172+
: SolutionApplicationTarget(expr, contextualPurpose,
1173+
TypeLoc::withoutLoc(convertType),
1174+
isDiscarded) { }
1175+
1176+
SolutionApplicationTarget(Expr *expr, ContextualTypePurpose contextualPurpose,
1177+
TypeLoc convertType, bool isDiscarded) {
11671178
kind = Kind::expression;
11681179
expression.expression = expr;
1180+
expression.contextualPurpose = contextualPurpose;
11691181
expression.convertType = convertType;
11701182
expression.isDiscarded = isDiscarded;
11711183
}
@@ -1189,16 +1201,31 @@ class SolutionApplicationTarget {
11891201
}
11901202
}
11911203

1204+
ContextualTypePurpose getExprContextualTypePurpose() const {
1205+
assert(kind == Kind::expression);
1206+
return expression.contextualPurpose;
1207+
}
1208+
11921209
Type getExprConversionType() const {
1210+
assert(kind == Kind::expression);
1211+
return expression.convertType.getType();
1212+
}
1213+
1214+
TypeLoc getExprConversionTypeLoc() const {
11931215
assert(kind == Kind::expression);
11941216
return expression.convertType;
11951217
}
11961218

11971219
void setExprConversionType(Type type) {
1220+
assert(kind == Kind::expression);
1221+
expression.convertType = TypeLoc::withoutLoc(type);
1222+
}
1223+
1224+
void setExprConversionTypeLoc(TypeLoc type) {
11981225
assert(kind == Kind::expression);
11991226
expression.convertType = type;
12001227
}
1201-
1228+
12021229
bool isDiscardedExpr() const {
12031230
assert(kind == Kind::expression);
12041231
return expression.isDiscarded;

lib/Sema/TypeCheckConstraints.cpp

+43-8
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,40 @@ bool GenericRequirementsCheckListener::diagnoseUnsatisfiedRequirement(
20012001
return false;
20022002
}
20032003

2004+
/// Whether the contextual type provided for the given purpose is only a
2005+
/// hint, and not a requirement.
2006+
static bool contextualTypeIsOnlyAHint(ContextualTypePurpose ctp,
2007+
TypeCheckExprOptions options) {
2008+
switch (ctp) {
2009+
case CTP_Initialization:
2010+
return !options.contains(
2011+
TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType);
2012+
case CTP_ForEachStmt:
2013+
return true;
2014+
case CTP_Unused:
2015+
case CTP_ReturnStmt:
2016+
case CTP_ReturnSingleExpr:
2017+
case CTP_YieldByValue:
2018+
case CTP_YieldByReference:
2019+
case CTP_ThrowStmt:
2020+
case CTP_EnumCaseRawValue:
2021+
case CTP_DefaultParameter:
2022+
case CTP_AutoclosureDefaultParameter:
2023+
case CTP_CalleeResult:
2024+
case CTP_CallArgument:
2025+
case CTP_ClosureResult:
2026+
case CTP_ArrayElement:
2027+
case CTP_DictionaryKey:
2028+
case CTP_DictionaryValue:
2029+
case CTP_CoerceOperand:
2030+
case CTP_AssignSource:
2031+
case CTP_SubscriptAssignSource:
2032+
case CTP_Condition:
2033+
case CTP_CannotFail:
2034+
return false;
2035+
}
2036+
}
2037+
20042038
#pragma mark High-level entry points
20052039
Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20062040
TypeLoc convertType,
@@ -2071,7 +2105,7 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20712105

20722106
// If the convertType is *only* provided for that hint, then null it out so
20732107
// that we don't later treat it as an actual conversion constraint.
2074-
if (options.contains(TypeCheckExprFlags::ConvertTypeIsOnlyAHint))
2108+
if (contextualTypeIsOnlyAHint(convertTypePurpose, options))
20752109
convertType = TypeLoc();
20762110

20772111
// If the client can handle unresolved type variables, leave them in the
@@ -2092,7 +2126,7 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20922126

20932127
// Attempt to solve the constraint system.
20942128
SolutionApplicationTarget target(
2095-
expr, convertTo,
2129+
expr, convertTypePurpose, convertTo,
20962130
options.contains(TypeCheckExprFlags::IsDiscarded));
20972131
auto viable = cs.solve(target, listener, allowFreeTypeVariables);
20982132
if (!viable)
@@ -2149,7 +2183,7 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
21492183
// Unless the client has disabled them, perform syntactic checks on the
21502184
// expression now.
21512185
if (!cs.shouldSuppressDiagnostics() &&
2152-
!options.contains(TypeCheckExprFlags::DisableStructuralChecks)) {
2186+
!options.contains(TypeCheckExprFlags::SubExpressionDiagnostics)) {
21532187
bool isExprStmt = options.contains(TypeCheckExprFlags::IsExprStmt);
21542188
performSyntacticExprDiagnostics(result, dc, isExprStmt);
21552189
}
@@ -2192,7 +2226,8 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc,
21922226
// re-check.
21932227
if (needClearType)
21942228
expr->setType(Type());
2195-
SolutionApplicationTarget target(expr, Type(), /*isDiscarded=*/false);
2229+
SolutionApplicationTarget target(
2230+
expr, CTP_Unused, Type(), /*isDiscarded=*/false);
21962231
auto viable = cs.solve(target, listener, allowFreeTypeVariables);
21972232
if (!viable) {
21982233
recoverOriginalType();
@@ -2272,7 +2307,8 @@ void TypeChecker::getPossibleTypesOfExpressionWithoutApplying(
22722307
if (originalType && originalType->hasError())
22732308
expr->setType(Type());
22742309

2275-
SolutionApplicationTarget target(expr, Type(), /*isDiscarded=*/false);
2310+
SolutionApplicationTarget target(
2311+
expr, CTP_Unused, Type(), /*isDiscarded=*/false);
22762312
if (auto viable = cs.solve(target, listener, allowFreeTypeVariables)) {
22772313
expr = target.getAsExpr();
22782314
for (auto &solution : *viable) {
@@ -2598,7 +2634,7 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
25982634

25992635
TypeLoc contextualType;
26002636
auto contextualPurpose = CTP_Unused;
2601-
TypeCheckExprOptions flags = TypeCheckExprFlags::ConvertTypeIsOnlyAHint;
2637+
TypeCheckExprOptions flags = None;
26022638

26032639
// Set the contextual purpose even if the pattern doesn't have a type so
26042640
// if there's an error we can use that information to inform diagnostics.
@@ -2617,7 +2653,6 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
26172653
// opaque type.
26182654
if (auto opaqueType = patternType->getAs<OpaqueTypeArchetypeType>()){
26192655
flags |= TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType;
2620-
flags -= TypeCheckExprFlags::ConvertTypeIsOnlyAHint;
26212656
}
26222657

26232658
// Only provide a TypeLoc if it makes sense to allow diagnostics.
@@ -2985,7 +3020,7 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
29853020
// Type-check the for-each loop sequence and element pattern.
29863021
auto resultTy = TypeChecker::typeCheckExpression(
29873022
seq, dc, TypeLoc::withoutLoc(sequenceProto->getDeclaredType()),
2988-
CTP_ForEachStmt, TypeCheckExprFlags::ConvertTypeIsOnlyAHint, &listener);
3023+
CTP_ForEachStmt, None, &listener);
29893024
if (!resultTy)
29903025
return true;
29913026
return false;

lib/Sema/TypeChecker.h

+3-24
Original file line numberDiff line numberDiff line change
@@ -163,31 +163,18 @@ enum class TypeCheckExprFlags {
163163
/// disables constraints forcing an lvalue result to be loadable.
164164
IsDiscarded = 0x01,
165165

166-
/// Whether the client wants to disable the structural syntactic restrictions
167-
/// that we force for style or other reasons.
168-
DisableStructuralChecks = 0x02,
169-
170166
/// If set, the client wants a best-effort solution to the constraint system,
171167
/// but can tolerate a solution where all of the constraints are solved, but
172168
/// not all type variables have been determined. In this case, the constraint
173169
/// system is not applied to the expression AST, but the ConstraintSystem is
174170
/// left in-tact.
175171
AllowUnresolvedTypeVariables = 0x08,
176172

177-
/// If set, the 'convertType' specified to typeCheckExpression should not
178-
/// produce a conversion constraint, but it should be used to guide the
179-
/// solution in terms of performance optimizations of the solver, and in terms
180-
/// of guiding diagnostics.
181-
ConvertTypeIsOnlyAHint = 0x10,
182-
183173
/// If set, this expression isn't embedded in a larger expression or
184174
/// statement. This should only be used for syntactic restrictions, and should
185175
/// not affect type checking itself.
186176
IsExprStmt = 0x20,
187177

188-
/// This is an inout yield.
189-
IsInOutYield = 0x100,
190-
191178
/// If set, a conversion constraint should be specified so that the result of
192179
/// the expression is an optional type.
193180
ExpressionTypeMustBeOptional = 0x200,
@@ -821,11 +808,9 @@ class TypeChecker final {
821808
/// to be possible.
822809
///
823810
/// \param convertType The type that the expression is being converted to,
824-
/// or null if the expression is standalone. If the 'ConvertTypeIsOnlyAHint'
825-
/// option is specified, then this is only a hint, it doesn't produce a full
826-
/// conversion constraint. The location information is only used for
827-
/// diagnostics should the conversion fail; it is safe to pass a TypeLoc
828-
/// without location information.
811+
/// or null if the expression is standalone. The location information is
812+
/// only used for diagnostics should the conversion fail; it is safe to pass
813+
/// a TypeLoc without location information.
829814
///
830815
/// \param options Options that control how type checking is performed.
831816
///
@@ -847,12 +832,6 @@ class TypeChecker final {
847832
ExprTypeCheckListener *listener = nullptr,
848833
constraints::ConstraintSystem *baseCS = nullptr);
849834

850-
static Type typeCheckExpression(Expr *&expr, DeclContext *dc,
851-
ExprTypeCheckListener *listener) {
852-
return TypeChecker::typeCheckExpression(expr, dc, TypeLoc(), CTP_Unused,
853-
TypeCheckExprOptions(), listener);
854-
}
855-
856835
/// Type check the given expression and return its type without
857836
/// applying the solution.
858837
///

0 commit comments

Comments
 (0)