Skip to content

[Type checker] Eliminate some unnecessary ExprTypeCheckListener subclasses #29588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ Optional<Diag<Type, Type>> GenericArgumentsMismatchFailure::getDiagnosticFor(
case CTP_ReturnSingleExpr:
return diag::cannot_convert_to_return_type;
case CTP_DefaultParameter:
case CTP_AutoclosureDefaultParameter:
return diag::cannot_convert_default_arg_value;
case CTP_YieldByValue:
return diag::cannot_convert_yield_value;
Expand Down Expand Up @@ -2085,6 +2086,7 @@ getContextualNilDiagnostic(ContextualTypePurpose CTP) {
case CTP_EnumCaseRawValue:
return diag::cannot_convert_raw_initializer_value_nil;
case CTP_DefaultParameter:
case CTP_AutoclosureDefaultParameter:
return diag::cannot_convert_default_arg_value_nil;
case CTP_YieldByValue:
return diag::cannot_convert_yield_value_nil;
Expand Down Expand Up @@ -2863,6 +2865,7 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
case CTP_EnumCaseRawValue:
return diag::cannot_convert_raw_initializer_value;
case CTP_DefaultParameter:
case CTP_AutoclosureDefaultParameter:
return forProtocol ? diag::cannot_convert_default_arg_value_protocol
: diag::cannot_convert_default_arg_value;
case CTP_YieldByValue:
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9130,6 +9130,7 @@ void ConstraintSystem::addContextualConversionConstraint(
case CTP_ThrowStmt:
case CTP_EnumCaseRawValue:
case CTP_DefaultParameter:
case CTP_AutoclosureDefaultParameter:
case CTP_ClosureResult:
case CTP_DictionaryKey:
case CTP_DictionaryValue:
Expand Down
69 changes: 19 additions & 50 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2107,6 +2107,14 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
}
}

// For an @autoclosure default parameter, we want to convert to the result
// type. Stash the autoclosure default parameter type.
FunctionType *autoclosureDefaultParamType = nullptr;
if (convertTypePurpose == CTP_AutoclosureDefaultParameter) {
autoclosureDefaultParamType = convertType.getType()->castTo<FunctionType>();
convertType.setType(autoclosureDefaultParamType->getResult());
}

// Tell the constraint system what the contextual type is. This informs
// diagnostics and is a hint for various performance optimizations.
// FIXME: Look through LoadExpr. This is an egregious hack due to the
Expand All @@ -2130,6 +2138,7 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
allowFreeTypeVariables = FreeTypeVariableBinding::UnresolvedType;

Type convertTo = convertType.getType();

if (options.contains(TypeCheckExprFlags::ExpressionTypeMustBeOptional)) {
assert(!convertTo && "convertType and type check options conflict");
auto *convertTypeLocator =
Expand Down Expand Up @@ -2175,6 +2184,12 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
}
result = resultTarget->getAsExpr();

// For an @autoclosure default parameter type, add the autoclosure
// conversion.
if (convertTypePurpose == CTP_AutoclosureDefaultParameter) {
result = cs.buildAutoClosureExpr(result, autoclosureDefaultParamType);
}

// Notify listener that we've applied the solution.
if (listener)
result = listener->appliedSolution(solution, result);
Expand Down Expand Up @@ -2204,32 +2219,9 @@ Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue,
DeclContext *DC, Type paramType,
bool isAutoClosure) {
assert(paramType && !paramType->hasError());

if (isAutoClosure) {
class AutoClosureListener : public ExprTypeCheckListener {
FunctionType *ParamType;

public:
AutoClosureListener(FunctionType *paramType)
: ParamType(paramType) {}

Expr *appliedSolution(constraints::Solution &solution,
Expr *expr) override {
auto &cs = solution.getConstraintSystem();
return cs.buildAutoClosureExpr(expr, ParamType);
}
};

auto *fnType = paramType->castTo<FunctionType>();
AutoClosureListener listener(fnType);
return typeCheckExpression(defaultValue, DC,
TypeLoc::withoutLoc(fnType->getResult()),
CTP_DefaultParameter, TypeCheckExprOptions(),
&listener);
}

return typeCheckExpression(defaultValue, DC, TypeLoc::withoutLoc(paramType),
CTP_DefaultParameter);
return typeCheckExpression(
defaultValue, DC, TypeLoc::withoutLoc(paramType),
isAutoClosure ? CTP_AutoclosureDefaultParameter : CTP_DefaultParameter);
}

Type TypeChecker::
Expand Down Expand Up @@ -3209,30 +3201,7 @@ bool TypeChecker::typeCheckExprPattern(ExprPattern *EP, DeclContext *DC,
/*Implicit=*/true);

// Check the expression as a condition.
//
// TODO: Type-check of `~=` operator can't (yet) use `typeCheckCondition`
// because that utilizes contextual type which interferes with diagnostics.
// We don't yet have a full access to pattern-matching context in
// constraint system, which is required to enable these situations
// to be properly diagnosed.
struct ConditionListener : public ExprTypeCheckListener {
// Add the appropriate Boolean constraint.
bool builtConstraints(ConstraintSystem &cs, Expr *expr) override {
// Otherwise, the result must be convertible to Bool.
auto boolDecl = cs.getASTContext().getBoolDecl();
if (!boolDecl)
return true;

// Condition must convert to Bool.
cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
boolDecl->getDeclaredType(),
cs.getConstraintLocator(expr));
return false;
}
};

ConditionListener listener;
bool hadError = !typeCheckExpression(matchCall, DC, &listener);
bool hadError = typeCheckCondition(matchCall, DC);
// Save the type-checked expression in the pattern.
EP->setMatchExpr(matchCall);
// Set the type on the pattern.
Expand Down
4 changes: 4 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ enum ContextualTypePurpose {
CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.

/// Default value in @autoclosure parameter
/// 'foo(a : @autoclosure () -> Int = 42)'.
CTP_AutoclosureDefaultParameter,

CTP_CalleeResult, ///< Constraint is placed on the result of a callee.
CTP_CallArgument, ///< Call to function or operator requires type.
CTP_ClosureResult, ///< Closure result expects a specific type.
Expand Down