Skip to content

Commit d981cf3

Browse files
committed
Sema: De-requestify TypeBase::isNoncopyable() and TypeBase::isEscapable()
And consolidate the logic in ConformanceLookup.cpp.
1 parent 4e971a4 commit d981cf3

File tree

7 files changed

+109
-164
lines changed

7 files changed

+109
-164
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -475,43 +475,6 @@ class InvertibleAnnotationRequest
475475
bool isCached() const { return true; }
476476
};
477477

478-
/// Determine whether the given type is Escapable.
479-
class IsEscapableRequest
480-
: public SimpleRequest<IsEscapableRequest, bool(CanType),
481-
RequestFlags::Cached> {
482-
public:
483-
using SimpleRequest::SimpleRequest;
484-
485-
private:
486-
friend SimpleRequest;
487-
488-
// Evaluation.
489-
bool evaluate(Evaluator &evaluator, CanType) const;
490-
491-
public:
492-
// Caching.
493-
bool isCached() const { return true; }
494-
};
495-
496-
/// Determine whether the given type is noncopyable. Assumes type parameters
497-
/// have become archetypes.
498-
class IsNoncopyableRequest
499-
: public SimpleRequest<IsNoncopyableRequest, bool(CanType),
500-
RequestFlags::Cached> {
501-
public:
502-
using SimpleRequest::SimpleRequest;
503-
504-
private:
505-
friend SimpleRequest;
506-
507-
// Evaluation.
508-
bool evaluate(Evaluator &evaluator, CanType type) const;
509-
510-
public:
511-
// Caching.
512-
bool isCached() const { return true; }
513-
};
514-
515478
/// Determine whether the given declaration is 'dynamic''.
516479
class IsDynamicRequest :
517480
public SimpleRequest<IsDynamicRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,6 @@ SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,
222222
SWIFT_REQUEST(TypeChecker, InvertibleAnnotationRequest,
223223
InverseMarking(TypeDecl *, InvertibleProtocolKind),
224224
Cached, NoLocationInfo)
225-
SWIFT_REQUEST(TypeChecker, IsNoncopyableRequest,
226-
bool (CanType),
227-
Cached, NoLocationInfo)
228-
SWIFT_REQUEST(TypeChecker, IsEscapableRequest,
229-
bool (CanType),
230-
Cached, NoLocationInfo)
231225
SWIFT_REQUEST(TypeChecker, IsGetterMutatingRequest, bool(AbstractStorageDecl *),
232226
SeparatelyCached, NoLocationInfo)
233227
SWIFT_REQUEST(TypeChecker, IsImplicitlyUnwrappedOptionalRequest,

lib/AST/ConformanceLookup.cpp

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,4 +750,95 @@ ModuleDecl::checkConformance(Type type, ProtocolDecl *proto,
750750
}
751751

752752
return lookupResult;
753-
}
753+
}
754+
755+
/// Returns true if this type is _always_ Copyable using the legacy check
756+
/// that does not rely on conformances.
757+
static bool alwaysNoncopyable(Type ty) {
758+
if (auto *nominal = ty->getNominalOrBoundGenericNominal())
759+
return !nominal->canBeCopyable();
760+
761+
if (auto *expansion = ty->getAs<PackExpansionType>()) {
762+
return alwaysNoncopyable(expansion->getPatternType());
763+
}
764+
765+
// if any components of the tuple are move-only, then the tuple is move-only.
766+
if (auto *tupl = ty->getCanonicalType()->getAs<TupleType>()) {
767+
for (auto eltTy : tupl->getElementTypes())
768+
if (alwaysNoncopyable(eltTy))
769+
return true;
770+
}
771+
772+
return false; // otherwise, the conservative assumption is it's copyable.
773+
}
774+
775+
/// Preprocesses a type before querying whether it conforms to an invertible.
776+
static CanType preprocessTypeForInvertibleQuery(Type orig) {
777+
Type type = orig;
778+
779+
// Strip off any StorageType wrapper.
780+
type = type->getReferenceStorageReferent();
781+
782+
// Pack expansions such as `repeat T` themselves do not have conformances,
783+
// so check its pattern type for conformance.
784+
if (auto *pet = type->getAs<PackExpansionType>()) {
785+
type = pet->getPatternType()->getCanonicalType();
786+
}
787+
788+
// Strip @lvalue and canonicalize.
789+
auto canType = type->getRValueType()->getCanonicalType();
790+
return canType;
791+
}
792+
793+
static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) {
794+
auto &ctx = type->getASTContext();
795+
796+
auto *proto = ctx.getProtocol(getKnownProtocolKind(ip));
797+
assert(proto && "missing Copyable/Escapable from stdlib!");
798+
799+
// Must not have a type parameter!
800+
assert(!type->hasTypeParameter() && "caller forgot to mapTypeIntoContext!");
801+
802+
assert(!type->is<PackExpansionType>());
803+
804+
// The SIL types in the AST do not have real conformances, and should have
805+
// been handled in SILType instead.
806+
assert(!(type->is<SILBoxType,
807+
SILMoveOnlyWrappedType,
808+
SILPackType,
809+
SILTokenType>()));
810+
811+
const bool conforms =
812+
(bool) proto->getParentModule()->checkConformance(
813+
type, proto,
814+
/*allowMissing=*/false);
815+
816+
return conforms;
817+
}
818+
819+
/// \returns true iff this type lacks conformance to Copyable.
820+
bool TypeBase::isNoncopyable() {
821+
auto canType = preprocessTypeForInvertibleQuery(this);
822+
auto &ctx = canType->getASTContext();
823+
824+
// for legacy-mode queries that are not dependent on conformances to Copyable
825+
if (!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics))
826+
return alwaysNoncopyable(canType);
827+
828+
return !conformsToInvertible(canType, InvertibleProtocolKind::Copyable);
829+
}
830+
831+
bool TypeBase::isEscapable() {
832+
auto canType = preprocessTypeForInvertibleQuery(this);
833+
auto &ctx = canType->getASTContext();
834+
835+
// for legacy-mode queries that are not dependent on conformances to Escapable
836+
if (!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
837+
if (auto nom = canType.getAnyNominal())
838+
return nom->canBeEscapable();
839+
else
840+
return true;
841+
}
842+
843+
return conformsToInvertible(canType, InvertibleProtocolKind::Escapable);
844+
}

lib/AST/Type.cpp

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -157,77 +157,6 @@ bool TypeBase::isMarkerExistential() {
157157
return true;
158158
}
159159

160-
/// Returns true if this type is _always_ Copyable using the legacy check
161-
/// that does not rely on conformances.
162-
static bool alwaysNoncopyable(Type ty) {
163-
if (auto *nominal = ty->getNominalOrBoundGenericNominal())
164-
return !nominal->canBeCopyable();
165-
166-
if (auto *expansion = ty->getAs<PackExpansionType>()) {
167-
return alwaysNoncopyable(expansion->getPatternType());
168-
}
169-
170-
// if any components of the tuple are move-only, then the tuple is move-only.
171-
if (auto *tupl = ty->getCanonicalType()->getAs<TupleType>()) {
172-
for (auto eltTy : tupl->getElementTypes())
173-
if (alwaysNoncopyable(eltTy))
174-
return true;
175-
}
176-
177-
return false; // otherwise, the conservative assumption is it's copyable.
178-
}
179-
180-
/// Preprocesses a type before querying whether it conforms to an invertible.
181-
static CanType preprocessTypeForInvertibleQuery(Type orig) {
182-
Type type = orig;
183-
184-
// Strip off any StorageType wrapper.
185-
type = type->getReferenceStorageReferent();
186-
187-
// Pack expansions such as `repeat T` themselves do not have conformances,
188-
// so check its pattern type for conformance.
189-
if (auto *pet = type->getAs<PackExpansionType>()) {
190-
type = pet->getPatternType()->getCanonicalType();
191-
}
192-
193-
// Strip @lvalue and canonicalize.
194-
auto canType = type->getRValueType()->getCanonicalType();
195-
return canType;
196-
}
197-
198-
/// \returns true iff this type lacks conformance to Copyable.
199-
bool TypeBase::isNoncopyable() {
200-
auto canType = preprocessTypeForInvertibleQuery(this);
201-
auto &ctx = canType->getASTContext();
202-
203-
// for legacy-mode queries that are not dependent on conformances to Copyable
204-
if (!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics))
205-
return alwaysNoncopyable(canType);
206-
207-
assert(!hasTypeParameter()
208-
&& "requires a contextual type; use mapTypeIntoContext");
209-
IsNoncopyableRequest request{canType};
210-
return evaluateOrDefault(ctx.evaluator, request, /*default=*/true);
211-
}
212-
213-
bool TypeBase::isEscapable() {
214-
auto canType = preprocessTypeForInvertibleQuery(this);
215-
auto &ctx = canType->getASTContext();
216-
217-
// for legacy-mode queries that are not dependent on conformances to Escapable
218-
if (!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
219-
if (auto nom = canType.getAnyNominal())
220-
return nom->canBeEscapable();
221-
else
222-
return true;
223-
}
224-
225-
assert(!hasTypeParameter()
226-
&& "requires a contextual type; use mapTypeIntoContext");
227-
IsEscapableRequest request{canType};
228-
return evaluateOrDefault(ctx.evaluator, request, /*default=*/false);
229-
}
230-
231160
bool TypeBase::isPlaceholder() {
232161
return is<PlaceholderType>();
233162
}

lib/Sema/CSFix.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,11 @@ TreatArrayLiteralAsDictionary::attempt(ConstraintSystem &cs, Type dictionaryTy,
213213
if (unwrappedDict->isTypeVariableOrMember())
214214
return nullptr;
215215

216-
if (!TypeChecker::conformsToKnownProtocol(
217-
unwrappedDict, KnownProtocolKind::ExpressibleByDictionaryLiteral,
218-
cs.DC->getParentModule()))
219-
return nullptr;
216+
auto &ctx = cs.getASTContext();
217+
218+
if (auto *proto = ctx.getProtocol(KnownProtocolKind::ExpressibleByDictionaryLiteral))
219+
if (!cs.DC->getParentModule()->lookupConformance(unwrappedDict, proto))
220+
return nullptr;
220221

221222
auto arrayLoc = cs.getConstraintLocator(arrayExpr);
222223
return new (cs.getAllocator())

lib/Sema/CSGen.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,10 +2092,12 @@ namespace {
20922092
}
20932093

20942094
Type visitArrayExpr(ArrayExpr *expr) {
2095+
auto &ctx = CS.getASTContext();
2096+
20952097
// An array expression can be of a type T that conforms to the
20962098
// ExpressibleByArrayLiteral protocol.
2097-
ProtocolDecl *arrayProto = TypeChecker::getProtocol(
2098-
CS.getASTContext(), expr->getLoc(),
2099+
auto *arrayProto = TypeChecker::getProtocol(
2100+
ctx, expr->getLoc(),
20992101
KnownProtocolKind::ExpressibleByArrayLiteral);
21002102
if (!arrayProto) {
21012103
return Type();
@@ -2149,12 +2151,15 @@ namespace {
21492151
auto *M = CS.DC->getParentModule();
21502152

21512153
auto type = contextualType->lookThroughAllOptionalTypes();
2152-
if (TypeChecker::conformsToKnownProtocol(
2153-
type, KnownProtocolKind::ExpressibleByArrayLiteral, M))
2154+
2155+
if (M->lookupConformance(type, arrayProto))
21542156
return false;
21552157

2156-
return TypeChecker::conformsToKnownProtocol(
2157-
type, KnownProtocolKind::ExpressibleByDictionaryLiteral, M);
2158+
if (auto *proto = ctx.getProtocol(KnownProtocolKind::ExpressibleByDictionaryLiteral))
2159+
if (M->lookupConformance(type, proto))
2160+
return true;
2161+
2162+
return false;
21582163
};
21592164

21602165
if (isDictionaryContextualType(contextualType)) {
@@ -2206,7 +2211,7 @@ namespace {
22062211

22072212
// The array element type defaults to 'Any'.
22082213
CS.addConstraint(ConstraintKind::Defaultable, arrayElementTy,
2209-
CS.getASTContext().getAnyExistentialType(), locator);
2214+
ctx.getAnyExistentialType(), locator);
22102215

22112216
return arrayTy;
22122217
}

lib/Sema/TypeCheckInvertible.cpp

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -156,44 +156,6 @@ static void tryEmitContainmentFixits(InFlightDiagnostic &&diag,
156156
}
157157
}
158158

159-
/// MARK: conformance queries
160-
161-
static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) {
162-
auto &ctx = type->getASTContext();
163-
164-
auto *proto = ctx.getProtocol(getKnownProtocolKind(ip));
165-
assert(proto && "missing Copyable/Escapable from stdlib!");
166-
167-
// Must not have a type parameter!
168-
assert(!type->hasTypeParameter() && "caller forgot to mapTypeIntoContext!");
169-
170-
assert(!type->is<PackExpansionType>());
171-
172-
// The SIL types in the AST do not have real conformances, and should have
173-
// been handled in SILType instead.
174-
assert(!(type->is<SILBoxType,
175-
SILMoveOnlyWrappedType,
176-
SILPackType,
177-
SILTokenType>()));
178-
179-
const bool conforms =
180-
(bool) proto->getParentModule()->checkConformance(
181-
type, proto,
182-
/*allowMissing=*/false);
183-
184-
return conforms;
185-
}
186-
187-
bool IsEscapableRequest::evaluate(Evaluator &evaluator,
188-
CanType type) const {
189-
return conformsToInvertible(type, InvertibleProtocolKind::Escapable);
190-
}
191-
192-
bool IsNoncopyableRequest::evaluate(Evaluator &evaluator,
193-
CanType type) const {
194-
return !conformsToInvertible(type, InvertibleProtocolKind::Copyable);
195-
}
196-
197159
/// MARK: conformance checking
198160
static bool checkInvertibleConformanceCommon(ProtocolConformance *conformance,
199161
InvertibleProtocolKind ip) {

0 commit comments

Comments
 (0)