Skip to content

[Type checker] Move TypeChecker::resolveType() into TypeResolution. #18868

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 7 commits into from
Aug 21, 2018
4 changes: 2 additions & 2 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1420,8 +1420,8 @@ namespace {
Type resolveTypeReferenceInExpression(TypeRepr *rep) {
TypeResolutionOptions options(TypeResolverContext::InExpression);
options |= TypeResolutionFlags::AllowUnboundGenerics;
return CS.TC.resolveType(rep, TypeResolution::forContextual(CS.DC),
options);
return TypeResolution::forContextual(CS.DC).resolveType(rep,
options);
}

Type visitTypeExpr(TypeExpr *E) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/CSSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1199,9 +1199,9 @@ void ConstraintSystem::shrink(Expr *expr) {
// instead of cloning representative.
auto coercionRepr = typeRepr->clone(CS.getASTContext());
// Let's try to resolve coercion type from cloned representative.
auto resolution = TypeResolution::forContextual(CS.DC);
auto coercionType =
CS.TC.resolveType(coercionRepr,
TypeResolution::forContextual(CS.DC), None);
resolution.resolveType(coercionRepr, None);

// Looks like coercion type is invalid, let's skip this sub-tree.
if (coercionType->hasError())
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/CodeSynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1848,8 +1848,8 @@ static void maybeAddAccessorsToBehaviorStorage(TypeChecker &TC, VarDecl *var) {
};

// Try to resolve the behavior to a protocol.
auto behaviorType = TC.resolveType(behavior->ProtocolName,
TypeResolution::forContextual(dc), None);
auto resolution = TypeResolution::forContextual(dc);
auto behaviorType = resolution.resolveType(behavior->ProtocolName, None);
if (!behaviorType) {
return makeBehaviorAccessors();
}
Expand Down
11 changes: 6 additions & 5 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ Type ConstraintSystem::openUnboundGenericType(UnboundGenericType *unbound,
// pointing at a generic TypeAliasDecl here. If we find a way to
// handle generic TypeAliases elsewhere, this can just become a
// call to BoundGenericType::get().
return TC.applyUnboundGenericArguments(
return TypeChecker::applyUnboundGenericArguments(
unbound, unboundDecl,
SourceLoc(), TypeResolution::forContextual(DC), arguments);
}
Expand Down Expand Up @@ -980,10 +980,11 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
// Unqualified reference to a type.
if (auto typeDecl = dyn_cast<TypeDecl>(value)) {
// Resolve the reference to this type declaration in our current context.
auto type = TC.resolveTypeInContext(typeDecl, nullptr,
TypeResolution::forContextual(useDC),
TypeResolverContext::InExpression,
/*isSpecialized=*/false);
auto type = TypeChecker::resolveTypeInContext(
typeDecl, nullptr,
TypeResolution::forContextual(useDC),
TypeResolverContext::InExpression,
/*isSpecialized=*/false);

// Open the type.
type = openUnboundGenericType(type, locator);
Expand Down
34 changes: 18 additions & 16 deletions lib/Sema/DerivedConformanceEquatableHashable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,23 @@ using namespace swift;
/// \p theEnum The enum whose elements and associated values should be checked.
/// \p protocol The protocol being requested.
/// \return True if all associated values of all elements of the enum conform.
static bool allAssociatedValuesConformToProtocol(TypeChecker &tc,
DeclContext *DC,
static bool allAssociatedValuesConformToProtocol(DeclContext *DC,
EnumDecl *theEnum,
ProtocolDecl *protocol) {
auto lazyResolver = DC->getASTContext().getLazyResolver();
for (auto elt : theEnum->getAllElements()) {
if (!elt->hasInterfaceType())
tc.validateDecl(elt);
lazyResolver->resolveDeclSignature(elt);

auto PL = elt->getParameterList();
if (!PL)
continue;

for (auto param : *PL) {
auto type = param->getType()->mapTypeOutOfContext();
if (!tc.conformsToProtocol(DC->mapTypeIntoContext(type), protocol, DC,
ConformanceCheckFlags::Used)) {
if (!TypeChecker::conformsToProtocol(DC->mapTypeIntoContext(type),
protocol, DC,
ConformanceCheckFlags::Used)) {
return false;
}
}
Expand All @@ -65,41 +66,42 @@ static bool allAssociatedValuesConformToProtocol(TypeChecker &tc,
/// \p theStruct The struct whose stored properties should be checked.
/// \p protocol The protocol being requested.
/// \return True if all stored properties of the struct conform.
static bool allStoredPropertiesConformToProtocol(TypeChecker &tc,
DeclContext *DC,
static bool allStoredPropertiesConformToProtocol(DeclContext *DC,
StructDecl *theStruct,
ProtocolDecl *protocol) {
auto lazyResolver = DC->getASTContext().getLazyResolver();
auto storedProperties =
theStruct->getStoredProperties(/*skipInaccessible=*/true);
for (auto propertyDecl : storedProperties) {
if (!propertyDecl->hasType())
tc.validateDecl(propertyDecl);
lazyResolver->resolveDeclSignature(propertyDecl);
if (!propertyDecl->hasType())
return false;

auto type = propertyDecl->getType()->mapTypeOutOfContext();
if (!tc.conformsToProtocol(DC->mapTypeIntoContext(type), protocol, DC,
ConformanceCheckFlags::Used)) {
if (!TypeChecker::conformsToProtocol(DC->mapTypeIntoContext(type),
protocol, DC,
ConformanceCheckFlags::Used)) {
return false;
}
}
return true;
}

/// Common preconditions for Equatable and Hashable.
static bool canDeriveConformance(TypeChecker &tc, DeclContext *DC,
static bool canDeriveConformance(DeclContext *DC,
NominalTypeDecl *target,
ProtocolDecl *protocol) {
// The type must be an enum or a struct.
if (auto enumDecl = dyn_cast<EnumDecl>(target)) {
// The cases must not have associated values, or all associated values must
// conform to the protocol.
return allAssociatedValuesConformToProtocol(tc, DC, enumDecl, protocol);
return allAssociatedValuesConformToProtocol(DC, enumDecl, protocol);
}

if (auto structDecl = dyn_cast<StructDecl>(target)) {
// All stored properties of the struct must conform to the protocol.
return allStoredPropertiesConformToProtocol(tc, DC, structDecl, protocol);
return allStoredPropertiesConformToProtocol(DC, structDecl, protocol);
}

return false;
Expand Down Expand Up @@ -675,12 +677,12 @@ deriveEquatable_eq(DerivedConformance &derived,
return eqDecl;
}

bool DerivedConformance::canDeriveEquatable(TypeChecker &tc, DeclContext *DC,
bool DerivedConformance::canDeriveEquatable(DeclContext *DC,
NominalTypeDecl *type) {
ASTContext &ctx = DC->getASTContext();
auto equatableProto = ctx.getProtocol(KnownProtocolKind::Equatable);
if (!equatableProto) return false;
return canDeriveConformance(tc, DC, type, equatableProto);
return canDeriveConformance(DC, type, equatableProto);
}

ValueDecl *DerivedConformance::deriveEquatable(ValueDecl *requirement) {
Expand Down Expand Up @@ -1187,7 +1189,7 @@ ValueDecl *DerivedConformance::deriveHashable(ValueDecl *requirement) {
// Refuse to synthesize Hashable if type isn't a struct or enum, or if it
// has non-Hashable stored properties/associated values.
auto hashableProto = C.getProtocol(KnownProtocolKind::Hashable);
if (!canDeriveConformance(TC, getConformanceContext(), Nominal,
if (!canDeriveConformance(getConformanceContext(), Nominal,
hashableProto)) {
TC.diagnose(ConformanceDecl->getLoc(), diag::type_does_not_conform,
Nominal->getDeclaredType(),
Expand Down
10 changes: 4 additions & 6 deletions lib/Sema/DerivedConformances.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ Type DerivedConformance::getProtocolType() const {
return Protocol->getDeclaredType();
}

bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC,
DeclContext *DC,
bool DerivedConformance::derivesProtocolConformance(DeclContext *DC,
NominalTypeDecl *Nominal,
ProtocolDecl *Protocol) {
// Only known protocols can be derived.
Expand All @@ -73,7 +72,7 @@ bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC,
// Enums without associated values can implicitly derive Equatable
// conformance.
case KnownProtocolKind::Equatable:
return canDeriveEquatable(TC, DC, Nominal);
return canDeriveEquatable(DC, Nominal);

// "Simple" enums without availability attributes can explicitly derive
// a CaseIterable conformance.
Expand Down Expand Up @@ -129,7 +128,7 @@ bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC,
if (auto structDecl = dyn_cast<StructDecl>(Nominal)) {
switch (*knownProtocol) {
case KnownProtocolKind::Equatable:
return canDeriveEquatable(TC, DC, Nominal);
return canDeriveEquatable(DC, Nominal);
default:
return false;
}
Expand Down Expand Up @@ -158,8 +157,7 @@ ValueDecl *DerivedConformance::getDerivableRequirement(TypeChecker &tc,
ConformanceCheckFlags::SkipConditionalRequirements)) {
auto DC = conformance->getConcrete()->getDeclContext();
// Check whether this nominal type derives conformances to the protocol.
if (!DerivedConformance::derivesProtocolConformance(tc, DC, nominal,
proto))
if (!DerivedConformance::derivesProtocolConformance(DC, nominal, proto))
return nullptr;
}

Expand Down
7 changes: 2 additions & 5 deletions lib/Sema/DerivedConformances.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,14 @@ class DerivedConformance {
/// declarations for requirements of the protocol that are not satisfied by
/// the type's explicit members.
///
/// \param tc The type checker.
///
/// \param nominal The nominal type for which we are determining whether to
/// derive a witness.
///
/// \param protocol The protocol whose requirements are being derived.
///
/// \return True if the type can implicitly derive a conformance for the
/// given protocol.
static bool derivesProtocolConformance(TypeChecker &tc, DeclContext *DC,
static bool derivesProtocolConformance(DeclContext *DC,
NominalTypeDecl *nominal,
ProtocolDecl *protocol);

Expand Down Expand Up @@ -120,8 +118,7 @@ class DerivedConformance {
/// associated values, and for structs with all-Equatable stored properties.
///
/// \returns True if the requirement can be derived.
static bool canDeriveEquatable(TypeChecker &tc, DeclContext *DC,
NominalTypeDecl *type);
static bool canDeriveEquatable(DeclContext *DC, NominalTypeDecl *type);

/// Derive an Equatable requirement for a type.
///
Expand Down
26 changes: 11 additions & 15 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1777,12 +1777,13 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
SmallPtrSet<TypeBase *, 4> constrainedGenericParams;

// Go over the set of requirements and resolve their types.
auto resolution = TypeResolution::forContextual(FD);
for (auto &req : trailingWhereClause->getRequirements()) {
if (req.getKind() == RequirementReprKind::SameType) {
auto firstType = TC.resolveType(req.getFirstTypeRepr(),
TypeResolution::forContextual(FD), None);
auto secondType = TC.resolveType(req.getSecondTypeRepr(),
TypeResolution::forContextual(FD), None);
auto firstType = resolution.resolveType(req.getFirstTypeRepr(),
None);
auto secondType = resolution.resolveType(req.getSecondTypeRepr(),
None);
Type interfaceFirstType;
Type interfaceSecondType;

Expand Down Expand Up @@ -1832,9 +1833,8 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
}

if (req.getKind() == RequirementReprKind::LayoutConstraint) {
auto subjectType = TC.resolveType(req.getSubjectRepr(),
TypeResolution::forContextual(FD),
None);
auto subjectType = resolution.resolveType(req.getSubjectRepr(),
None);
Type interfaceSubjectType;

// Map types to their interface types.
Expand Down Expand Up @@ -1870,12 +1870,8 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
}

if (req.getKind() == RequirementReprKind::TypeConstraint) {
auto subjectType = TC.resolveType(req.getSubjectRepr(),
TypeResolution::forContextual(FD),
None);
auto constraint = TC.resolveType(req.getConstraintLoc().getTypeRepr(),
TypeResolution::forContextual(FD),
None);
auto subjectType = resolution.resolveType(req.getSubjectRepr(), None);
auto constraint = resolution.resolveType(req.getConstraintLoc().getTypeRepr(), None);

Type interfaceSubjectType;

Expand Down Expand Up @@ -2043,8 +2039,8 @@ void AttributeChecker::visitImplementsAttr(ImplementsAttr *attr) {
options |= TypeResolutionFlags::AllowUnboundGenerics;

DeclContext *DC = D->getDeclContext();
Type T = TC.resolveType(ProtoTypeLoc.getTypeRepr(),
TypeResolution::forContextual(DC), options);
auto resolution = TypeResolution::forContextual(DC);
Type T = resolution.resolveType(ProtoTypeLoc.getTypeRepr(), options);
ProtoTypeLoc.setType(T);

// Definite error-types were already diagnosed in resolveType.
Expand Down
6 changes: 3 additions & 3 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,7 @@ namespace {
if (auto PlaceholderE = dyn_cast<EditorPlaceholderExpr>(expr)) {
if (!PlaceholderE->getTypeLoc().isNull()) {
if (!TC.validateType(PlaceholderE->getTypeLoc(),
TypeResolution::forContextual(DC)))
TypeResolution::forContextual(DC), None))
expr->setType(PlaceholderE->getTypeLoc().getType());
}
return finish(true, expr);
Expand Down Expand Up @@ -1347,7 +1347,7 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) {
options |= TypeResolutionFlags::AllowUnboundGenerics;
options |= TypeResolutionFlags::AllowUnavailable;
auto resolution = TypeResolution::forContextual(DC);
auto BaseTy = TC.resolveType(InnerTypeRepr, resolution, options);
auto BaseTy = resolution.resolveType(InnerTypeRepr, options);

if (BaseTy && BaseTy->mayHaveMembers()) {
auto lookupOptions = defaultMemberLookupOptions;
Expand Down Expand Up @@ -1864,7 +1864,7 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) {
TypeResolutionOptions options(TypeResolverContext::InExpression);
options |= TypeResolutionFlags::AllowUnboundGenerics;
auto resolution = TypeResolution::forContextual(DC);
type = TC.resolveType(rep, resolution, options);
type = resolution.resolveType(rep, options);
typeExpr->getTypeLoc().setType(type);
}

Expand Down
6 changes: 4 additions & 2 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3818,8 +3818,10 @@ void TypeChecker::validateDecl(ValueDecl *D) {
TypeLoc &defaultDefinition = assocType->getDefaultDefinitionLoc();
if (!defaultDefinition.isNull()) {
if (validateType(
defaultDefinition,
TypeResolution::forContextual(assocType->getDeclContext()))) {
defaultDefinition,
TypeResolution::forContextual(
assocType->getDeclContext()),
None)) {
defaultDefinition.setInvalidType(Context);
} else {
// associatedtype X = X is invalid
Expand Down
7 changes: 5 additions & 2 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1068,14 +1068,17 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
}
break;

case RequirementKind::Superclass:
case RequirementKind::Superclass: {
// Superclass requirements.
if (!isSubclassOf(firstType, secondType, dc)) {
// FIXME: Don't use the type checker instance here?
TypeChecker &tc = static_cast<TypeChecker &>(*ctx.getLazyResolver());
if (!tc.isSubclassOf(firstType, secondType, dc)) {
diagnostic = diag::type_does_not_inherit;
diagnosticNote = diag::type_does_not_inherit_or_conform_requirement;
requirementFailure = true;
}
break;
}

case RequirementKind::SameType:
if (!firstType->isEqual(secondType)) {
Expand Down
14 changes: 9 additions & 5 deletions lib/Sema/TypeCheckNameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
if (options.contains(NameLookupFlags::IgnoreAccessControl))
subOptions |= NL_IgnoreAccessControl;

if (!dc->lookupQualified(type, name, subOptions, this, decls))
if (!dc->lookupQualified(type, name, subOptions, nullptr, decls))
return result;

// Look through the declarations, keeping only the unique type declarations.
Expand All @@ -457,9 +457,11 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
auto *typeDecl = cast<TypeDecl>(decl);

// FIXME: This should happen before we attempt shadowing checks.
validateDecl(typeDecl);
if (!typeDecl->hasInterfaceType()) // FIXME: recursion-breaking hack
continue;
if (!typeDecl->hasInterfaceType()) {
dc->getASTContext().getLazyResolver()->resolveDeclSignature(typeDecl);
if (!typeDecl->hasInterfaceType()) // FIXME: recursion-breaking hack
continue;
}

auto memberType = typeDecl->getDeclaredInterfaceType();

Expand Down Expand Up @@ -548,7 +550,9 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
ProtocolConformanceState::CheckingTypeWitnesses)
continue;

auto typeDecl = concrete->getTypeWitnessAndDecl(assocType, this).second;
auto lazyResolver = dc->getASTContext().getLazyResolver();
auto typeDecl =
concrete->getTypeWitnessAndDecl(assocType, lazyResolver).second;

assert(typeDecl && "Missing type witness?");

Expand Down
Loading