Skip to content

[NFC] Introduce isType and getDeclType #27195

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

Closed
wants to merge 2 commits into from
Closed
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
8 changes: 4 additions & 4 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,10 @@ class ASTContext final {

#define KNOWN_STDLIB_TYPE_DECL(NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \
/** Retrieve the declaration of Swift.NAME. */ \
DECL_CLASS *get##NAME##Decl() const;
DECL_CLASS *get##NAME##Decl() const; \
\
/** Retrieve the type of Swift.NAME. */ \
Type get##NAME##Type() const;
#include "swift/AST/KnownStdlibTypes.def"

/// Retrieve the declaration of Swift.Optional<T>.Some.
Expand All @@ -475,9 +478,6 @@ class ASTContext final {
/// Retrieve the type Swift.AnyObject.
CanType getAnyObjectType() const;

/// Retrieve the type Swift.Never.
CanType getNeverType() const;

#define KNOWN_OBJC_TYPE_DECL(MODULE, NAME, DECL_CLASS) \
/** Retrieve the declaration of MODULE.NAME. */ \
DECL_CLASS *get##NAME##Decl() const; \
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/KnownProtocols.def
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ PROTOCOL(OptionSet)
PROTOCOL(CaseIterable)
PROTOCOL(SIMDScalar)
PROTOCOL(BinaryInteger)
PROTOCOL(RangeReplaceableCollection)

PROTOCOL_(BridgedNSError)
PROTOCOL_(BridgedStoredNSError)
Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/KnownStdlibTypes.def
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
#define KNOWN_STDLIB_TYPE_DECL(NAME, DECL_CLASS, NUM_GENERIC_PARAMS)
#endif

KNOWN_STDLIB_TYPE_DECL(Void, TypeAliasDecl, 0)

KNOWN_STDLIB_TYPE_DECL(Bool, NominalTypeDecl, 0)

KNOWN_STDLIB_TYPE_DECL(Int, NominalTypeDecl, 0)
Expand Down Expand Up @@ -89,6 +87,5 @@ KNOWN_STDLIB_TYPE_DECL(Encoder, ProtocolDecl, 1)
KNOWN_STDLIB_TYPE_DECL(Decoder, ProtocolDecl, 1)
KNOWN_STDLIB_TYPE_DECL(KeyedEncodingContainer, NominalTypeDecl, 1)
KNOWN_STDLIB_TYPE_DECL(KeyedDecodingContainer, NominalTypeDecl, 1)
KNOWN_STDLIB_TYPE_DECL(RangeReplaceableCollection, ProtocolDecl, 1)

#undef KNOWN_STDLIB_TYPE_DECL
8 changes: 5 additions & 3 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -774,11 +774,13 @@ class alignas(1 << TypeAlignInBits) TypeBase {
/// These are the types of the Swift type system.
bool isLegalFormalType();

/// Check if this type is equal to the empty tuple type.
// Whether or not this is equal to ()
bool isVoid();

/// Check if this type is equal to Swift.Bool.
bool isBool();
#define KNOWN_STDLIB_TYPE_DECL(NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \
/** Whether or not this is equal to Swift.NAME. */ \
bool is##NAME();
#include "swift/AST/KnownStdlibTypes.def"

/// Check if this type is equal to Builtin.IntN.
bool isBuiltinIntegerType(unsigned bitWidth);
Expand Down
78 changes: 32 additions & 46 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ FuncDecl *ASTContext::getPlusFunctionOnRangeReplaceableCollection() const {
for (auto Req: FD->getGenericRequirements()) {
if (Req.getKind() == RequirementKind::Conformance &&
Req.getSecondType()->getNominalOrBoundGenericNominal() ==
getRangeReplaceableCollectionDecl()) {
getProtocol(KnownProtocolKind::RangeReplaceableCollection)) {
getImpl().PlusFunctionOnRangeReplaceableCollection = FD;
}
}
Expand All @@ -693,17 +693,13 @@ FuncDecl *ASTContext::getPlusFunctionOnString() const {
if (!FD->getOperatorDecl())
continue;
auto ResultType = FD->getResultInterfaceType();
if (ResultType->getNominalOrBoundGenericNominal() != getStringDecl())
if (!ResultType->isString())
continue;
auto ParamList = FD->getParameters();
if (ParamList->size() != 2)
continue;
auto CheckIfStringParam = [this](ParamDecl* Param) {
auto Type = Param->getInterfaceType()->getNominalOrBoundGenericNominal();
return Type == getStringDecl();
};
if (CheckIfStringParam(ParamList->get(0)) &&
CheckIfStringParam(ParamList->get(1))) {
if (ParamList->get(0)->getInterfaceType()->isString() &&
ParamList->get(1)->getInterfaceType()->isString()) {
getImpl().PlusFunctionOnString = FD;
break;
}
Expand Down Expand Up @@ -738,22 +734,28 @@ FuncDecl *ASTContext::getSequenceMakeIterator() const {
}

#define KNOWN_STDLIB_TYPE_DECL(NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \
DECL_CLASS *ASTContext::get##NAME##Decl() const { \
if (getImpl().NAME##Decl) \
return getImpl().NAME##Decl; \
SmallVector<ValueDecl *, 1> results; \
lookupInSwiftModule(#NAME, results); \
for (auto result : results) { \
if (auto type = dyn_cast<DECL_CLASS>(result)) { \
auto params = type->getGenericParams(); \
if (NUM_GENERIC_PARAMS == (params == nullptr ? 0 : params->size())) { \
getImpl().NAME##Decl = type; \
return type; \
} \
DECL_CLASS *ASTContext::get##NAME##Decl() const { \
if (getImpl().NAME##Decl) \
return getImpl().NAME##Decl; \
SmallVector<ValueDecl *, 1> results; \
lookupInSwiftModule(#NAME, results); \
for (auto result : results) { \
if (auto type = dyn_cast<DECL_CLASS>(result)) { \
auto params = type->getGenericParams(); \
if (NUM_GENERIC_PARAMS == (params == nullptr ? 0 : params->size())) { \
getImpl().NAME##Decl = type; \
return type; \
} \
} \
return nullptr; \
}
} \
return nullptr; \
} \
\
Type ASTContext::get##NAME##Type() const { \
if (!get##NAME##Decl()) \
return Type(); \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the one thing I'm worried about. Clients of these accessors are historically terrible at handling the case where the lookup fails. That's why some of the TypeChecker entrypoints try to detect this, emit a diagnostic, and map the null type to an ErrorType. There shouldn't be any clients of this function before Sema, so maybe we should just look into doing that everywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slava pointed out in a previous commit that I did that perhaps if these accessors fail to just fail loudly because other pipelines of the compiler aren't great at handling whether or not they failed. Would that ease your concern, or should we still diagnose and provide an error type still?

return get##NAME##Decl()->getDeclaredInterfaceType(); \
}
#include "swift/AST/KnownStdlibTypes.def"

CanType ASTContext::getExceptionType() const {
Expand Down Expand Up @@ -846,13 +848,6 @@ CanType ASTContext::getAnyObjectType() const {
return getImpl().AnyObjectType;
}

CanType ASTContext::getNeverType() const {
auto neverDecl = getNeverDecl();
if (!neverDecl)
return CanType();
return neverDecl->getDeclaredType()->getCanonicalType();
}

#define KNOWN_OBJC_TYPE_DECL(MODULE, NAME, DECLTYPE) \
DECLTYPE *ASTContext::get##NAME##Decl() const { \
if (!getImpl().NAME##Decl) { \
Expand Down Expand Up @@ -1088,19 +1083,18 @@ FuncDecl *getBinaryComparisonOperatorIntDecl(const ASTContext &C, StringRef op,
if (!C.getIntDecl() || !C.getBoolDecl())
return nullptr;

auto intType = C.getIntDecl()->getDeclaredType();
auto isIntParam = [&](AnyFunctionType::Param param) {
return (!param.isVariadic() && !param.isInOut() &&
param.getPlainType()->isEqual(intType));
param.getPlainType()->isInt());
};
auto boolType = C.getBoolDecl()->getDeclaredType();
auto decl = lookupOperatorFunc(C, op, intType,
[=](FunctionType *type) {

auto decl = lookupOperatorFunc(C, op, C.getIntType(),
[=](FunctionType *type) {
// Check for the signature: (Int, Int) -> Bool
if (type->getParams().size() != 2) return false;
if (!isIntParam(type->getParams()[0]) ||
!isIntParam(type->getParams()[1])) return false;
return type->getResult()->isEqual(boolType);
return type->getResult()->isBool();
});
cached = decl;
return decl;
Expand Down Expand Up @@ -1155,11 +1149,7 @@ FuncDecl *ASTContext::getArrayAppendElementDecl() const {
return nullptr;

auto SelfInOutTy = SelfDecl->getInterfaceType();
BoundGenericStructType *SelfGenericStructTy =
SelfInOutTy->getAs<BoundGenericStructType>();
if (!SelfGenericStructTy)
return nullptr;
if (SelfGenericStructTy->getDecl() != getArrayDecl())
if (!SelfInOutTy->isArray())
return nullptr;

auto ParamList = FnDecl->getParameters();
Expand Down Expand Up @@ -1202,11 +1192,7 @@ FuncDecl *ASTContext::getArrayReserveCapacityDecl() const {
return nullptr;

auto SelfInOutTy = SelfDecl->getInterfaceType();
BoundGenericStructType *SelfGenericStructTy =
SelfInOutTy->getAs<BoundGenericStructType>();
if (!SelfGenericStructTy)
return nullptr;
if (SelfGenericStructTy->getDecl() != getArrayDecl())
if (!SelfInOutTy->isArray())
return nullptr;

auto ParamList = FnDecl->getParameters();
Expand Down Expand Up @@ -4371,7 +4357,7 @@ Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type,
[&](KnownProtocolKind known) -> ProtocolConformanceRef {
// Don't ascribe any behavior to Optional other than what we explicitly
// give it. We don't want things like AnyObject?? to work.
if (type->getAnyNominal() == getOptionalDecl())
if (type->isOptional())
return ProtocolConformanceRef::forInvalid();

// Find the protocol.
Expand Down
8 changes: 3 additions & 5 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3777,23 +3777,21 @@ class TypePrinter : public TypeVisitor<TypePrinter> {

void visitBoundGenericType(BoundGenericType *T) {
if (Options.SynthesizeSugarOnTypes) {
auto *NT = T->getDecl();
auto &Ctx = T->getASTContext();
if (NT == Ctx.getArrayDecl()) {
if (T->isArray()) {
Printer << "[";
visit(T->getGenericArgs()[0]);
Printer << "]";
return;
}
if (NT == Ctx.getDictionaryDecl()) {
if (T->isDictionary()) {
Printer << "[";
visit(T->getGenericArgs()[0]);
Printer << " : ";
visit(T->getGenericArgs()[1]);
Printer << "]";
return;
}
if (NT == Ctx.getOptionalDecl()) {
if (T->isOptional()) {
printWithParensIfNotSimple(T->getGenericArgs()[0]);
Printer << "?";
return;
Expand Down
47 changes: 20 additions & 27 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1032,8 +1032,7 @@ class Verifier : public ASTWalker {
case StmtConditionElement::CK_Boolean: {
auto *E = elt.getBoolean();
if (shouldVerifyChecked(E))
checkSameType(E->getType(), Ctx.getBoolDecl()->getDeclaredType(),
"condition type");
checkSameType(E->getType(), Ctx.getBoolType(), "condition type");
break;
}

Expand Down Expand Up @@ -1376,9 +1375,7 @@ class Verifier : public ASTWalker {
}

// Ensure we don't convert an array to a void pointer this way.

if (fromElement->getNominalOrBoundGenericNominal() == Ctx.getArrayDecl()
&& toElement->isEqual(Ctx.TheEmptyTupleType)) {
if (fromElement->isArray() && toElement->isVoid()) {
Out << "InOutToPointer is converting an array to a void pointer; "
"ArrayToPointer should be used instead:\n";
E->dump(Out);
Expand All @@ -1401,7 +1398,7 @@ class Verifier : public ASTWalker {
// The source may be optionally inout.
auto fromArray = E->getSubExpr()->getType()->getInOutObjectType();

if (fromArray->getNominalOrBoundGenericNominal() != Ctx.getArrayDecl()) {
if (!fromArray->isArray()) {
Out << "ArrayToPointer does not convert from array:\n";
E->dump(Out);
Out << "\n";
Expand All @@ -1422,8 +1419,7 @@ class Verifier : public ASTWalker {
PrettyStackTraceExpr debugStack(Ctx,
"verifying StringToPointer", E);

if (E->getSubExpr()->getType()->getNominalOrBoundGenericNominal()
!= Ctx.getStringDecl()) {
if (!E->getSubExpr()->getType()->isString()) {
Out << "StringToPointer does not convert from string:\n";
E->dump(Out);
Out << "\n";
Expand Down Expand Up @@ -2188,22 +2184,20 @@ class Verifier : public ASTWalker {
auto keyPathTy = E->getKeyPath()->getType();
auto resultTy = E->getType();

if (auto nom = keyPathTy->getAs<NominalType>()) {
if (nom->getDecl() == Ctx.getAnyKeyPathDecl()) {
// AnyKeyPath application is <T> rvalue T -> rvalue Any?
if (baseTy->is<LValueType>()) {
Out << "AnyKeyPath application base is not an rvalue\n";
abort();
}
auto resultObjTy = resultTy->getOptionalObjectType();
if (!resultObjTy || !resultObjTy->isAny()) {
Out << "AnyKeyPath application result must be Any?\n";
abort();
}
return;
if (keyPathTy->isAnyKeyPath()) {
// AnyKeyPath application is <T> rvalue T -> rvalue Any?
if (baseTy->is<LValueType>()) {
Out << "AnyKeyPath application base is not an rvalue\n";
abort();
}
auto resultObjTy = resultTy->getOptionalObjectType();
if (!resultObjTy || !resultObjTy->isAny()) {
Out << "AnyKeyPath application result must be Any?\n";
abort();
}
return;
} else if (auto bgt = keyPathTy->getAs<BoundGenericType>()) {
if (bgt->getDecl() == Ctx.getPartialKeyPathDecl()) {
if (keyPathTy->isPartialKeyPath()) {
// PartialKeyPath<T> application is rvalue T -> rvalue Any
if (!baseTy->isEqual(bgt->getGenericArgs()[0])) {
Out << "PartialKeyPath application base doesn't match type\n";
Expand All @@ -2214,7 +2208,7 @@ class Verifier : public ASTWalker {
abort();
}
return;
} else if (bgt->getDecl() == Ctx.getKeyPathDecl()) {
} else if (keyPathTy->isKeyPath()) {
// KeyPath<T, U> application is rvalue T -> rvalue U
if (!baseTy->isEqual(bgt->getGenericArgs()[0])) {
Out << "KeyPath application base doesn't match type\n";
Expand All @@ -2225,7 +2219,7 @@ class Verifier : public ASTWalker {
abort();
}
return;
} else if (bgt->getDecl() == Ctx.getWritableKeyPathDecl()) {
} else if (keyPathTy->isWritableKeyPath()) {
// WritableKeyPath<T, U> application is
// lvalue T -> lvalue U
// or rvalue T -> rvalue U
Expand All @@ -2247,7 +2241,7 @@ class Verifier : public ASTWalker {
abort();
}
return;
} else if (bgt->getDecl() == Ctx.getReferenceWritableKeyPathDecl()) {
} else if (keyPathTy->isReferenceWritableKeyPath()) {
// ReferenceWritableKeyPath<T, U> application is
// rvalue T -> lvalue U
// or lvalue T -> lvalue U
Expand Down Expand Up @@ -2873,8 +2867,7 @@ class Verifier : public ASTWalker {
// Verify that the optionality of the result type of the
// initializer matches the failability of the initializer.
if (!CD->isInvalid() &&
CD->getDeclContext()->getDeclaredInterfaceType()->getAnyNominal() !=
Ctx.getOptionalDecl()) {
!CD->getDeclContext()->getDeclaredInterfaceType()->isOptional()) {
bool resultIsOptional = (bool) CD->getResultInterfaceType()
->getOptionalObjectType();
auto declIsOptional = CD->isFailable();
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1268,8 +1268,8 @@ static ValueDecl *getLinearFunctionConstructor(
static ValueDecl *getGlobalStringTablePointer(ASTContext &Context,
Identifier Id) {
// String -> Builtin.RawPointer
auto stringType = NominalType::get(Context.getStringDecl(), Type(), Context);
return getBuiltinFunction(Id, {stringType}, Context.TheRawPointerType);
return getBuiltinFunction(Id, {Context.getStringType()},
Context.TheRawPointerType);
}

static ValueDecl *getConvertStrongToUnownedUnsafe(ASTContext &ctx,
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/DiagnosticEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ static bool isInterestingTypealias(Type type) {
else
return false;

if (aliasDecl == type->getASTContext().getVoidDecl())
if (type->isVoid())
return false;

// The 'Swift.AnyObject' typealias is not 'interesting'.
Expand Down
Loading