Skip to content

[Sema] Decouple ConstraintSystem and TypeChecker headers #34206

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 6 commits into from
Oct 7, 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
6 changes: 3 additions & 3 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4296,7 +4296,7 @@ namespace {
{ Identifier() });

auto resultTy = TypeChecker::typeCheckExpression(
callExpr, cs.DC, valueType, CTP_CannotFail);
callExpr, cs.DC, /*contextualInfo=*/{valueType, CTP_CannotFail});
assert(resultTy && "Conversion cannot fail!");
(void)resultTy;

Expand Down Expand Up @@ -8026,8 +8026,8 @@ static Optional<SolutionApplicationTarget> applySolutionToForEachStmt(
Expr *convertElementExpr = elementExpr;
if (TypeChecker::typeCheckExpression(
convertElementExpr, dc,
optPatternType,
CTP_CoerceOperand).isNull()) {
/*contextualInfo=*/{optPatternType, CTP_CoerceOperand})
.isNull()) {
return None;
}
elementExpr->setIsPlaceholder(false);
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "ConstraintGraph.h"
#include "ConstraintSystem.h"
#include "TypeChecker.h"
#include "llvm/ADT/SetVector.h"
#include <tuple>

Expand Down
2 changes: 2 additions & 0 deletions lib/Sema/CSClosure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
//===----------------------------------------------------------------------===//

#include "ConstraintSystem.h"
#include "TypeChecker.h"

using namespace swift;
using namespace swift::constraints;

Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CSDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "Constraint.h"
#include "ConstraintSystem.h"
#include "OverloadChoice.h"
#include "TypeChecker.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/Decl.h"
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "ConstraintGraph.h"
#include "ConstraintSystem.h"
#include "TypeCheckType.h"
#include "TypeChecker.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Expr.h"
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CSRanking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//
//===----------------------------------------------------------------------===//
#include "ConstraintSystem.h"
#include "TypeChecker.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CSSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "ConstraintSystem.h"
#include "SolutionResult.h"
#include "TypeCheckType.h"
#include "TypeChecker.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/TypeWalker.h"
#include "llvm/ADT/STLExtras.h"
Expand Down
37 changes: 37 additions & 0 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "CSDiagnostics.h"
#include "CSFix.h"
#include "SolutionResult.h"
#include "TypeChecker.h"
#include "TypeCheckType.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/GenericEnvironment.h"
Expand Down Expand Up @@ -5215,3 +5216,39 @@ Type ConstraintSystem::getVarType(const VarDecl *var) {
return HoleType::get(Context, const_cast<VarDecl *>(var));
});
}

bool ConstraintSystem::isReadOnlyKeyPathComponent(
const AbstractStorageDecl *storage, SourceLoc referenceLoc) {
// See whether key paths can store to this component. (Key paths don't
// get any special power from being formed in certain contexts, such
// as the ability to assign to `let`s in initialization contexts, so
// we pass null for the DC to `isSettable` here.)
if (!getASTContext().isSwiftVersionAtLeast(5)) {
// As a source-compatibility measure, continue to allow
// WritableKeyPaths to be formed in the same conditions we did
// in previous releases even if we should not be able to set
// the value in this context.
if (!storage->isSettable(DC)) {
// A non-settable component makes the key path read-only, unless
// a reference-writable component shows up later.
return true;
}
} else if (!storage->isSettable(nullptr) ||
!storage->isSetterAccessibleFrom(DC)) {
// A non-settable component makes the key path read-only, unless
// a reference-writable component shows up later.
return true;
}

// If the setter is unavailable, then the keypath ought to be read-only
// in this context.
if (auto setter = storage->getOpaqueAccessor(AccessorKind::Set)) {
auto maybeUnavail =
TypeChecker::checkDeclarationAvailability(setter, referenceLoc, DC);
if (maybeUnavail.hasValue()) {
return true;
}
}

return false;
}
123 changes: 85 additions & 38 deletions lib/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@
#include "ConstraintGraphScope.h"
#include "ConstraintLocator.h"
#include "OverloadChoice.h"
#include "TypeChecker.h"
#include "SolutionResult.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/AnyFunctionRef.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/OptionSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetOperations.h"
Expand All @@ -49,15 +53,32 @@
namespace swift {

class Expr;
class FuncDecl;
class BraseStmt;
enum class TypeCheckExprFlags;

namespace constraints {

class ConstraintGraph;
class ConstraintGraphNode;
class ConstraintSystem;
class SolutionApplicationTarget;

} // end namespace constraints

// Forward declare some TypeChecker related functions
// so they could be made friends of ConstraintSystem.
namespace TypeChecker {

Optional<BraceStmt *> applyFunctionBuilderBodyTransform(FuncDecl *func,
Type builderType);

Optional<constraints::SolutionApplicationTarget>
typeCheckExpression(constraints::SolutionApplicationTarget &target,
OptionSet<TypeCheckExprFlags> options);

} // end namespace TypeChecker

} // end namespace swift

/// Allocate memory within the given constraint system.
Expand All @@ -66,6 +87,57 @@ void *operator new(size_t bytes, swift::constraints::ConstraintSystem& cs,

namespace swift {

/// This specifies the purpose of the contextual type, when specified to
/// typeCheckExpression. This is used for diagnostic generation to produce more
/// specified error messages when the conversion fails.
///
enum ContextualTypePurpose {
CTP_Unused, ///< No contextual type is specified.
CTP_Initialization, ///< Pattern binding initialization.
CTP_ReturnStmt, ///< Value specified to a 'return' statement.
CTP_ReturnSingleExpr, ///< Value implicitly returned from a function.
CTP_YieldByValue, ///< By-value yield operand.
CTP_YieldByReference, ///< By-reference yield operand.
CTP_ThrowStmt, ///< Value specified to a 'throw' statement.
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.
CTP_ArrayElement, ///< ArrayExpr wants elements to have a specific type.
CTP_DictionaryKey, ///< DictionaryExpr keys should have a specific type.
CTP_DictionaryValue, ///< DictionaryExpr values should have a specific type.
CTP_CoerceOperand, ///< CoerceExpr operand coerced to specific type.
CTP_AssignSource, ///< AssignExpr source operand coerced to result type.
CTP_SubscriptAssignSource, ///< AssignExpr source operand coerced to subscript
///< result type.
CTP_Condition, ///< Condition expression of various statements e.g.
///< `if`, `for`, `while` etc.
CTP_ForEachStmt, ///< "expression/sequence" associated with 'for-in' loop
///< is expected to conform to 'Sequence' protocol.
CTP_WrappedProperty, ///< Property type expected to match 'wrappedValue' type
CTP_ComposedPropertyWrapper, ///< Composed wrapper type expected to match
///< former 'wrappedValue' type

CTP_CannotFail, ///< Conversion can never fail. abort() if it does.
};

/// Specify how we handle the binding of underconstrained (free) type variables
/// within a solution to a constraint system.
enum class FreeTypeVariableBinding {
/// Disallow any binding of such free type variables.
Disallow,
/// Allow the free type variables to persist in the solution.
Allow,
/// Bind the type variables to UnresolvedType to represent the ambiguity.
UnresolvedType
};

namespace constraints {

/// Describes the algorithm to use for trailing closure matching.
Expand Down Expand Up @@ -857,6 +929,14 @@ struct ContextualTypeInfo {
TypeLoc typeLoc;
ContextualTypePurpose purpose;

ContextualTypeInfo() : typeLoc(TypeLoc()), purpose(CTP_Unused) {}

ContextualTypeInfo(Type contextualTy, ContextualTypePurpose purpose)
: typeLoc(TypeLoc::withoutLoc(contextualTy)), purpose(purpose) {}

ContextualTypeInfo(TypeLoc typeLoc, ContextualTypePurpose purpose)
: typeLoc(typeLoc), purpose(purpose) {}

Type getType() const { return typeLoc.getType(); }
};

Expand Down Expand Up @@ -2671,9 +2751,10 @@ class ConstraintSystem {
friend Optional<BraceStmt *>
swift::TypeChecker::applyFunctionBuilderBodyTransform(FuncDecl *func,
Type builderType);

friend Optional<SolutionApplicationTarget>
swift::TypeChecker::typeCheckExpression(SolutionApplicationTarget &target,
TypeCheckExprOptions options);
swift::TypeChecker::typeCheckExpression(
SolutionApplicationTarget &target, OptionSet<TypeCheckExprFlags> options);

/// Emit the fixes computed as part of the solution, returning true if we were
/// able to emit an error message, or false if none of the fixits worked out.
Expand Down Expand Up @@ -4912,41 +4993,7 @@ class ConstraintSystem {
llvm::function_ref<bool(Constraint *)> pred);

bool isReadOnlyKeyPathComponent(const AbstractStorageDecl *storage,
SourceLoc referenceLoc) {
// See whether key paths can store to this component. (Key paths don't
// get any special power from being formed in certain contexts, such
// as the ability to assign to `let`s in initialization contexts, so
// we pass null for the DC to `isSettable` here.)
if (!getASTContext().isSwiftVersionAtLeast(5)) {
// As a source-compatibility measure, continue to allow
// WritableKeyPaths to be formed in the same conditions we did
// in previous releases even if we should not be able to set
// the value in this context.
if (!storage->isSettable(DC)) {
// A non-settable component makes the key path read-only, unless
// a reference-writable component shows up later.
return true;
}
} else if (!storage->isSettable(nullptr) ||
!storage->isSetterAccessibleFrom(DC)) {
// A non-settable component makes the key path read-only, unless
// a reference-writable component shows up later.
return true;
}

// If the setter is unavailable, then the keypath ought to be read-only
// in this context.
if (auto setter = storage->getOpaqueAccessor(AccessorKind::Set)) {
auto maybeUnavail = TypeChecker::checkDeclarationAvailability(setter,
referenceLoc,
DC);
if (maybeUnavail.hasValue()) {
return true;
}
}

return false;
}
SourceLoc referenceLoc);

public:
// Given a type variable, attempt to find the disjunction of
Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/DebuggerTestingTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ class DebuggerTestingTransform : public ASTWalker {
// TODO: typeCheckExpression() seems to assign types to everything here,
// but may not be sufficient in some cases.
Expr *FinalExpr = ClosureCall;
if (!TypeChecker::typeCheckExpression(FinalExpr, getCurrentDeclContext()))
if (!TypeChecker::typeCheckExpression(FinalExpr, getCurrentDeclContext(),
/*contextualInfo=*/{}))
llvm::report_fatal_error("Could not type-check instrumentation");

// Captures have to be computed after the closure is type-checked. This
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/InstrumenterSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ bool InstrumenterBase::doTypeCheckImpl(ASTContext &Ctx, DeclContext *DC,
DiagnosticSuppression suppression(Ctx.Diags);
ErrorGatherer errorGatherer(Ctx.Diags);

TypeChecker::typeCheckExpression(parsedExpr, DC);
TypeChecker::typeCheckExpression(parsedExpr, DC, /*contextualInfo=*/{});

if (parsedExpr) {
ErrorFinder errorFinder;
Expand Down
1 change: 0 additions & 1 deletion lib/Sema/InstrumenterSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
//===----------------------------------------------------------------------===//

#include "TypeChecker.h"

#include "swift/AST/ASTWalker.h"

namespace swift {
Expand Down
3 changes: 1 addition & 2 deletions lib/Sema/TypeCheckCodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -962,8 +962,7 @@ bool swift::typeCheckExpression(DeclContext *DC, Expr *&parsedExpr) {
parsedExpr = parsedExpr->walk(SanitizeExpr(ctx, /*shouldReusePrecheckedType=*/false));

DiagnosticSuppression suppression(ctx.Diags);
auto resultTy = TypeChecker::typeCheckExpression(parsedExpr, DC, Type(),
CTP_Unused);
auto resultTy = TypeChecker::typeCheckExpression(parsedExpr, DC);
return !resultTy;
}

Expand Down
19 changes: 10 additions & 9 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,10 @@ void constraints::performSyntacticDiagnosticsForTarget(

#pragma mark High-level entry points
Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
Type convertType,
ContextualTypePurpose convertTypePurpose,
ContextualTypeInfo contextualInfo,
TypeCheckExprOptions options) {
SolutionApplicationTarget target(
expr, dc, convertTypePurpose, convertType,
expr, dc, contextualInfo.purpose, contextualInfo.getType(),
options.contains(TypeCheckExprFlags::IsDiscarded));
auto resultTarget = typeCheckExpression(target, options);
if (!resultTarget) {
Expand Down Expand Up @@ -422,9 +421,10 @@ Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue,
DeclContext *DC, Type paramType,
bool isAutoClosure) {
assert(paramType && !paramType->hasError());
return typeCheckExpression(
defaultValue, DC, paramType,
isAutoClosure ? CTP_AutoclosureDefaultParameter : CTP_DefaultParameter);
return typeCheckExpression(defaultValue, DC, /*contextualInfo=*/
{paramType, isAutoClosure
? CTP_AutoclosureDefaultParameter
: CTP_DefaultParameter});
}

bool TypeChecker::typeCheckBinding(
Expand Down Expand Up @@ -593,7 +593,8 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
// If this expression is already typechecked and has type Bool, then just
// re-typecheck it.
if (expr->getType() && expr->getType()->isBool()) {
auto resultTy = TypeChecker::typeCheckExpression(expr, dc);
auto resultTy =
TypeChecker::typeCheckExpression(expr, dc);
return !resultTy;
}

Expand All @@ -602,8 +603,8 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
return true;

auto resultTy = TypeChecker::typeCheckExpression(
expr, dc, boolDecl->getDeclaredInterfaceType(),
CTP_Condition);
expr, dc,
/*contextualInfo=*/{boolDecl->getDeclaredInterfaceType(), CTP_Condition});
return !resultTy;
}

Expand Down
Loading