blob: d57a4a331f3bd1d76b7b2633635214997bec3a77 [file] [log] [blame]
//===--- QuoteTransform.cpp - Quote transformation ------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements routines associated with the transformation used to
// desugar #quote(...) expressions.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/TypeVisitor.h"
#include "swift/AST/USRGeneration.h"
using namespace swift;
namespace {
class Breadcrumbs {
private:
SmallVector<SourceRange, 16> locs;
public:
template <typename T> void push(T quotee) {
locs.push_back(quotee->getSourceRange());
}
void push(Type quotee) { locs.push_back(SourceRange()); }
void pop() { locs.pop_back(); }
SourceLoc getLoc() {
for (auto loc : llvm::reverse(locs)) {
if (loc.isValid()) {
return loc.Start;
}
}
return SourceLoc();
}
};
class Breadcrumb {
private:
Breadcrumbs &bcs;
public:
template <typename T> Breadcrumb(Breadcrumbs &bcs, T quotee) : bcs(bcs) {
bcs.push(quotee);
}
~Breadcrumb() { bcs.pop(); }
};
class AbstractQuoter {
protected:
TypeChecker &tc;
ASTContext &ctx;
Breadcrumbs &bcs;
AbstractQuoter(TypeChecker &tc, Breadcrumbs &bcs)
: tc(tc), ctx(tc.Context), bcs(bcs) {}
Expr *quoteArray(ArrayRef<Expr *> quotedTrees) {
auto arrayExpr =
ArrayExpr::create(ctx, SourceLoc(), quotedTrees, {}, SourceLoc());
arrayExpr->setImplicit();
return arrayExpr;
}
Expr *quoteBool(bool val) {
return new (ctx) BooleanLiteralExpr(val, SourceLoc(), /*Implicit=*/true);
}
Expr *quoteFloat(StringRef val) {
return new (ctx) FloatLiteralExpr(val, SourceLoc(), /*Implicit=*/true);
}
Expr *quoteInt(StringRef val) {
return new (ctx) IntegerLiteralExpr(val, SourceLoc(), /*Implicit=*/true);
}
Expr *quoteInt(unsigned val) {
return IntegerLiteralExpr::createFromUnsigned(ctx, val);
}
Expr *quoteString(StringRef str) {
return new (ctx) StringLiteralExpr(str, SourceLoc(), /*Implicit=*/true);
}
Expr *quoteSymbol(ValueDecl *decl) {
if (decl) {
auto usr = allocateString(
[&](raw_ostream &os) { return ide::printDeclUSR(decl, os); });
return usr.empty() ? unknownSymbol(decl) : quoteString(usr);
} else {
return unknownSymbol(decl);
}
}
// TODO(TF-735): Implement ExpressibleByQuoteLiteral.
Expr *makeQuote(const char *name, ArrayRef<Expr *> quotedSubnodes) {
auto nodeInit = new (ctx) UnresolvedDeclRefExpr(
ctx.getIdentifier(name), DeclRefKind::Ordinary, DeclNameLoc());
return CallExpr::createImplicit(ctx, nodeInit, quotedSubnodes, {});
}
template <typename T> Expr *unknownName(T culprit) {
diagnoseUnsupported(culprit);
return makeQuote("Name", {quoteString("<?>"), quoteString(""),
makeQuote("UnknownTree", {})});
}
template <typename T> Expr *unknownTree(T culprit) {
diagnoseUnsupported(culprit);
return makeQuote("UnknownTree", {});
}
template <typename T> Expr *unknownSymbol(T culprit) {
diagnoseUnsupported(culprit);
return quoteString("");
}
template <typename T> void diagnoseUnsupported(T culprit) {
if (culprit) {
auto str =
allocateString([&](raw_ostream &os) { return culprit->dump(os); });
tc.diagnose(bcs.getLoc(), diag::quote_literal_unsupported_detailed, str);
} else {
tc.diagnose(bcs.getLoc(), diag::quote_literal_unsupported_brief);
}
}
private:
StringRef allocateString(std::function<void(raw_ostream &)> printer) {
llvm::SmallString<256> SS;
llvm::raw_svector_ostream OS(SS);
printer(OS);
auto str = SS.str();
if (str.empty()) {
return str;
} else {
char *Mem = static_cast<char *>(ctx.Allocate(str.size(), 1));
std::copy(str.begin(), str.end(), Mem);
return StringRef(Mem, str.size());
}
}
};
class TypeQuoter : public TypeVisitor<TypeQuoter, Expr *>,
private AbstractQuoter {
public:
TypeQuoter(TypeChecker &tc, Breadcrumbs &bcs) : AbstractQuoter(tc, bcs) {}
#define UNSUPPORTED_TYPE(TYPE) \
Expr *visit##TYPE(TYPE *type) { return unknownTree(type); }
Expr *visitAnyFunctionType(AnyFunctionType *type) {
SmallVector<Expr *, 4> attrs;
switch (type->getExtInfo().getDifferentiabilityKind()) {
case DifferentiabilityKind::NonDifferentiable:
break;
case DifferentiabilityKind::Normal:
attrs.push_back(makeQuote("Differentiable", {}));
break;
case DifferentiabilityKind::Linear:
attrs.push_back(makeQuote("DifferentiableLinear", {}));
break;
}
SmallVector<Type, 4> paramTypes;
for (auto param : type->getParams()) {
paramTypes.push_back(param.getOldType());
}
return makeQuote("FunctionType", {quoteArray(attrs), quoteTypes(paramTypes),
quoteType(type->getResult())});
}
Expr *visitAnyMetatypeType(AnyMetatypeType *type) {
return makeQuote("MetaType", {quoteType(type->getInstanceType())});
}
Expr *visitArraySliceType(ArraySliceType *type) {
return makeQuote("ArrayType", {quoteType(type->getBaseType())});
}
Expr *visitBoundGenericType(BoundGenericType *type) {
return makeQuote("SpecializedType", {quoteName(type->getDecl()),
quoteTypes(type->getGenericArgs())});
}
// NOTE: From what I understand, these types are created later in the
// pipeline so they cannot occur in code that is being quoted.
UNSUPPORTED_TYPE(BuiltinType)
Expr *visitDictionaryType(DictionaryType *type) {
return makeQuote("DictionaryType", {quoteType(type->getKeyType()),
quoteType(type->getValueType())});
}
// NOTE: From what I understand, these types don't occur in expressions
// and only occur in declarations, so we aren't interested in them until
// supporting other decls becomes a thing (#5).
UNSUPPORTED_TYPE(DependentMemberType)
UNSUPPORTED_TYPE(DynamicSelfType)
// NOTE: If typechecking encountered errors, there's no point in quoting
// anyway because none of that code will make it to runtime.
UNSUPPORTED_TYPE(ErrorType)
Expr *visitInOutType(InOutType *type) {
return makeQuote("InoutType", {quoteType(type->getObjectType())});
}
Expr *visitLValueType(LValueType *type) {
return makeQuote("LValueType", {quoteType(type->getObjectType())});
}
// NOTE: Since we ignore base in visitDotSyntaxBaseIgnoredExpr, from what
// I understand, module types cannot reach type quoters.
UNSUPPORTED_TYPE(ModuleType)
Expr *visitNominalType(NominalType *type) {
return quoteName(type->getDecl());
}
Expr *visitOptionalType(OptionalType *type) {
return makeQuote("OptionalType", {quoteType(type->getBaseType())});
}
Expr *visitParenType(ParenType *type) {
return quoteType(type->getUnderlyingType());
}
Expr *visitProtocolCompositionType(ProtocolCompositionType *type) {
return makeQuote("AndType", {quoteTypes(type->getMembers())});
}
// NOTE: From what I understand, these types don't occur in expressions
// and only occur in declarations, so we aren't interested in them until
// supporting other decls becomes a thing (#5).
UNSUPPORTED_TYPE(ReferenceStorageType)
UNSUPPORTED_TYPE(SubstitutableType)
// NOTE: From what I understand, these types are created later in the
// pipeline so they cannot occur in code that is being quoted.
UNSUPPORTED_TYPE(SILBlockStorageType)
UNSUPPORTED_TYPE(SILBoxType)
UNSUPPORTED_TYPE(SILFunctionType)
UNSUPPORTED_TYPE(SILTokenType)
Expr *visitTupleType(TupleType *type) {
return makeQuote("TupleType", {quoteTypes(type->getElementTypes())});
}
Expr *visitTypeAliasType(TypeAliasType *type) {
return quoteName(type->getDecl());
}
// NOTE: If typechecking encountered errors, there's no point in quoting
// anyway because none of that code will make it to runtime.
UNSUPPORTED_TYPE(TypeVariableType)
UNSUPPORTED_TYPE(UnboundGenericType)
UNSUPPORTED_TYPE(UnresolvedType)
#undef UNSUPPORTED_TYPE
private:
Expr *quoteName(TypeDecl *decl) {
return makeQuote(
"TypeName",
{quoteString(decl->getBaseName().userFacingName()), quoteSymbol(decl)});
}
Expr *quoteType(Type type) { return visit(type); }
template <typename T> Expr *quoteTypes(T types) {
SmallVector<Expr *, 4> quotedTypes;
for (auto type : types) {
quotedTypes.push_back(quoteType(type));
}
return quoteArray(quotedTypes);
}
};
class ASTQuoter
: public ASTVisitor<ASTQuoter, Expr *, Expr *, Expr *, void, void, void>,
private AbstractQuoter {
TypeQuoter typeQuoter;
public:
ASTQuoter(TypeChecker &tc, Breadcrumbs &bcs)
: AbstractQuoter(tc, bcs), typeQuoter(TypeQuoter(tc, bcs)) {}
#define UNSUPPORTED_EXPR(EXPR) \
Expr *visit##EXPR(EXPR *expr) { \
Breadcrumb bc(bcs, expr); \
return unknownTree(expr); \
}
Expr *visitArrayExpr(ArrayExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("ArrayLiteral", {quoteExprs(expr->getElements()),
quoteType(expr->getType())});
}
// NOTE: If typechecking encountered errors, there's no point in quoting
// anyway because none of that code will make it to runtime.
UNSUPPORTED_EXPR(ArrowExpr)
Expr *visitAssignExpr(AssignExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Assign",
{quoteExpr(expr->getDest()), quoteExpr(expr->getSrc()),
quoteType(expr->getType())});
}
Expr *visitAutoClosureExpr(AutoClosureExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Closure",
{quoteParams(expr->getParameters()),
quoteBody(expr->getBody()), quoteType(expr->getType())});
}
Expr *visitBinaryExpr(BinaryExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Binary", {quoteExpr(expr->getArg()->getElements()[0]),
quoteExpr(expr->getFn()),
quoteExpr(expr->getArg()->getElements()[1]),
quoteType(expr->getType())});
}
// TODO(TF-723): Quote optional chaining.
UNSUPPORTED_EXPR(BindOptionalExpr)
Expr *visitBooleanLiteralExpr(BooleanLiteralExpr *expr) {
Breadcrumb bc(bcs, expr);
// TODO(TF-733): Figure out why this is not good enough.
// auto type = expr->getType();
auto type = ctx.getBoolDecl()->getDeclaredType();
return makeQuote("BooleanLiteral",
{quoteBool(expr->getValue()), quoteType(type)});
}
Expr *visitCallerDefaultArgumentExpr(CallerDefaultArgumentExpr *expr) {
Breadcrumb bc(bcs, expr);
return quoteExpr(expr->getSubExpr());
}
Expr *visitCallExpr(CallExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Call",
{quoteExpr(expr->getFn()),
quoteLabels(expr->getArgumentLabels()),
quoteArgs(expr->getArg()), quoteType(expr->getType())});
}
Expr *visitCaptureListExpr(CaptureListExpr *expr) {
Breadcrumb bc(bcs, expr);
return quoteExpr(expr->getClosureBody());
}
Expr *visitClosureExpr(ClosureExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Closure",
{quoteParams(expr->getParameters()),
quoteBody(expr->getBody()), quoteType(expr->getType())});
}
// NOTE: There's no point in quoting IDE support artifacts.
UNSUPPORTED_EXPR(CodeCompletionExpr)
Expr *visitCoerceExpr(CoerceExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote(
"As", {quoteExpr(expr->getSubExpr()), quoteType(expr->getType())});
}
Expr *visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("OptionalAs", {quoteExpr(expr->getSubExpr()),
quoteType(expr->getCastTypeLoc().getType()),
quoteType(expr->getType())});
}
Expr *visitConstructorRefCallExpr(ConstructorRefCallExpr *expr) {
// TODO(TF-715): Allow @quoted on more decls.
Breadcrumb bc(bcs, expr);
if (auto ref = dyn_cast<DeclRefExpr>(expr->getFn())) {
return makeQuote("Name", {quoteValue(ref->getDeclRef()),
quoteSymbol(ref->getDecl()),
quoteType(expr->getType())});
} else {
return unknownTree(expr);
}
}
// NOTE: DeclQuoteExprs are only used in synthetic code generated for @quoted
// declarations, and that cannot end up quoted.
UNSUPPORTED_EXPR(DeclQuoteExpr)
Expr *visitDeclRefExpr(DeclRefExpr *expr) {
Breadcrumb bc(bcs, expr);
auto quotedExpr = makeQuote("Name", {quoteValue(expr->getDeclRef()),
quoteSymbol(expr->getDecl()),
quoteType(expr->getType())});
if (auto attr = expr->getDecl()->getAttrs().getAttribute<QuotedAttr>()) {
auto quoteRef = new (ctx)
DeclRefExpr(ConcreteDeclRef(attr->getQuoteDecl()), DeclNameLoc(),
/*Implicit=*/true);
auto quoteCall = CallExpr::createImplicit(ctx, quoteRef, {}, {});
auto &tc = TypeChecker::createForContext(ctx);
auto type = tc.getTypeOfQuoteExpr(expr->getType(), expr->getLoc());
return makeQuote("Unquote", {quotedExpr, quoteCall, quoteType(type)});
} else {
return quotedExpr;
}
}
Expr *visitDefaultArgumentExpr(DefaultArgumentExpr *expr) {
Breadcrumb bc(bcs, expr);
// TODO(TF-741): Look up the corresponding decl.
return makeQuote("Default", {quoteString(""), quoteType(expr->getType())});
}
Expr *visitDictionaryExpr(DictionaryExpr *expr) {
Breadcrumb bc(bcs, expr);
SmallVector<Expr *, 4> quotedExprs;
for (auto element : expr->getElements()) {
if (auto tuple = dyn_cast<TupleExpr>(element)) {
for (auto element : tuple->getElements()) {
quotedExprs.push_back(quoteExpr(element));
}
} else {
Breadcrumb bc2(bcs, element);
quotedExprs.push_back(unknownTree(element));
}
}
return makeQuote("DictionaryLiteral",
{quoteArray(quotedExprs), quoteType(expr->getType())});
}
Expr *visitDiscardAssignmentExpr(DiscardAssignmentExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Wildcard", {});
}
// TODO(TF-723): Quote type(of:).
UNSUPPORTED_EXPR(DynamicTypeExpr)
Expr *visitDotSelfExpr(DotSelfExpr *expr) {
Breadcrumb bc(bcs, expr);
if (auto base = dyn_cast<TypeExpr>(expr->getSubExpr())) {
// TODO(TF-730): Figure out why we can't simply do `base->getType()`.
if (auto metaType = expr->getType()->getAs<MetatypeType>()) {
return makeQuote("PostfixSelf", {quoteType(metaType->getInstanceType()),
quoteType(expr->getType())});
} else {
return unknownTree(expr);
}
} else {
return makeQuote("PostfixSelf", {quoteExpr(expr->getSubExpr()),
quoteType(expr->getType())});
}
}
Expr *visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *expr) {
Breadcrumb bc(bcs, expr);
if (auto ref = dyn_cast<DeclRefExpr>(expr->getRHS())) {
// TODO(TF-730): Figure out why this is not enough.
auto baseType = expr->getLHS()->getType();
auto refType = ref->getType();
if (!baseType || !refType) {
if (auto exprType = expr->getType()->getAs<FunctionType>()) {
baseType = exprType->getParams()[0].getPlainType();
refType = exprType->getResult();
} else {
return unknownTree(expr);
}
}
auto quotedExpr =
makeQuote("Name", {quoteValue(ref->getDeclRef()),
quoteSymbol(ref->getDecl()), quoteType(refType)});
if (auto attr = ref->getDecl()->getAttrs().getAttribute<QuotedAttr>()) {
auto quoteRef = new (ctx)
DeclRefExpr(ConcreteDeclRef(attr->getQuoteDecl()), DeclNameLoc(),
/*Implicit=*/true);
auto quoteBase = TypeExpr::createImplicit(baseType, ctx);
auto quoteDot =
new (ctx) DotSyntaxCallExpr(quoteRef, SourceLoc(), quoteBase);
auto quoteCall = CallExpr::createImplicit(ctx, quoteDot, {}, {});
auto &tc = TypeChecker::createForContext(ctx);
auto type = tc.getTypeOfQuoteExpr(refType, ref->getLoc());
return makeQuote("Unquote", {quotedExpr, quoteCall, quoteType(type)});
} else {
return quotedExpr;
}
} else {
return unknownTree(expr);
}
}
Expr *visitDotSyntaxCallExpr(DotSyntaxCallExpr *expr) {
Breadcrumb bc(bcs, expr);
if (auto ref = dyn_cast<DeclRefExpr>(expr->getFn())) {
if (dyn_cast<TypeExpr>(expr->getBase())) {
// TODO(TF-715): Allow @quoted on more decls.
return makeQuote("Name", {quoteValue(ref->getDeclRef()),
quoteSymbol(ref->getDecl()),
quoteType(expr->getType())});
} else {
auto quotedExpr = makeQuote("Member", {quoteExpr(expr->getBase()),
quoteValue(ref->getDeclRef()),
quoteSymbol(ref->getDecl()),
quoteType(expr->getType())});
if (auto attr = ref->getDecl()->getAttrs().getAttribute<QuotedAttr>()) {
auto quoteRef = new (ctx)
DeclRefExpr(ConcreteDeclRef(attr->getQuoteDecl()), DeclNameLoc(),
/*Implicit=*/true);
auto quoteBase =
TypeExpr::createImplicit(expr->getBase()->getType(), ctx);
auto quoteDot =
new (ctx) DotSyntaxCallExpr(quoteRef, SourceLoc(), quoteBase);
auto quoteCall = CallExpr::createImplicit(ctx, quoteDot, {}, {});
auto &tc = TypeChecker::createForContext(ctx);
auto type = tc.getTypeOfQuoteExpr(expr->getType(), expr->getLoc());
return makeQuote("Unquote", {quotedExpr, quoteCall, quoteType(type)});
} else {
return quotedExpr;
}
}
} else {
return unknownTree(expr);
}
}
// TODO(TF-723): Quote dynamic lookup exprs.
UNSUPPORTED_EXPR(DynamicLookupExpr)
// NOTE: There's no point in quoting IDE support artifacts.
UNSUPPORTED_EXPR(EditorPlaceholderExpr)
Expr *visitEnumIsCaseExpr(EnumIsCaseExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Is",
{quoteExpr(expr->getSubExpr()),
quoteType(expr->getEnumElement()->getInterfaceType()),
quoteType(expr->getType())});
}
// NOTE: If typechecking encountered errors, there's no point in quoting
// anyway because none of that code will make it to runtime.
UNSUPPORTED_EXPR(ErrorExpr)
Expr *visitFloatLiteralExpr(FloatLiteralExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("FloatLiteral", {quoteFloat(expr->getDigitsText()),
quoteType(expr->getType())});
}
Expr *visitForcedCheckedCastExpr(ForcedCheckedCastExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote(
"ForceAs", {quoteExpr(expr->getSubExpr()), quoteType(expr->getType())});
}
Expr *visitForceTryExpr(ForceTryExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("ForceTry", {quoteExpr(expr->getSubExpr()),
quoteType(expr->getType())});
}
Expr *visitForceValueExpr(ForceValueExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote(
"Force", {quoteExpr(expr->getSubExpr()), quoteType(expr->getType())});
}
Expr *visitIfExpr(IfExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Ternary", {quoteExpr(expr->getCondExpr()),
quoteExpr(expr->getThenExpr()),
quoteExpr(expr->getElseExpr()),
quoteType(expr->getType())});
}
Expr *visitImplicitConversionExpr(ImplicitConversionExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Conversion", {quoteExpr(expr->getSubExpr()),
quoteType(expr->getType())});
}
Expr *visitInOutExpr(InOutExpr *expr) {
Breadcrumb bc(bcs, expr);
// NOTE: If this expression is implicit, `expr` stands for a conversion that
// is sometimes emitted when inout parameters are used.
// Otherwise, `expr` stands for an in-out expression `&foo`.
if (expr->isImplicit()) {
return makeQuote("Conversion", {quoteExpr(expr->getSubExpr()),
quoteType(expr->getType())});
} else {
return makeQuote(
"Inout", {quoteExpr(expr->getSubExpr()), quoteType(expr->getType())});
}
}
Expr *visitIntegerLiteralExpr(IntegerLiteralExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("IntegerLiteral", {quoteInt(expr->getDigitsText()),
quoteType(expr->getType())});
}
Expr *
visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *expr) {
Breadcrumb bc(bcs, expr);
/// TODO(TF-723): Finish the implementation.
return makeQuote("StringInterpolation", {quoteType(expr->getType())});
}
Expr *visitIsExpr(IsExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Is", {quoteExpr(expr->getSubExpr()),
quoteType(expr->getCastTypeLoc().getType()),
quoteType(expr->getType())});
}
// TODO(TF-723): Quote key paths.
UNSUPPORTED_EXPR(KeyPathApplicationExpr)
UNSUPPORTED_EXPR(KeyPathDotExpr)
UNSUPPORTED_EXPR(KeyPathExpr)
Expr *visitLazyInitializerExpr(LazyInitializerExpr *expr) {
Breadcrumb bc(bcs, expr);
return quoteExpr(expr->getSubExpr());
}
Expr *visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *expr) {
Breadcrumb bc(bcs, expr);
StringRef kind;
switch (expr->getKind()) {
case MagicIdentifierLiteralExpr::File:
kind = "file";
break;
case MagicIdentifierLiteralExpr::Line:
kind = "line";
break;
case MagicIdentifierLiteralExpr::Column:
kind = "column";
break;
case MagicIdentifierLiteralExpr::Function:
kind = "function";
break;
case MagicIdentifierLiteralExpr::DSOHandle:
kind = "dsohandle";
break;
}
return makeQuote("MagicLiteral",
{quoteString(kind), quoteType(expr->getType())});
}
Expr *visitMakeTemporarilyEscapableExpr(MakeTemporarilyEscapableExpr *expr) {
Breadcrumb bc(bcs, expr);
return quoteExpr(expr->getSubExpr());
}
Expr *visitMemberRefExpr(MemberRefExpr *expr) {
// TODO(TF-715): Allow @quoted on more decls.
Breadcrumb bc(bcs, expr);
if (dyn_cast<TypeExpr>(expr->getBase())) {
return makeQuote("Name", {quoteValue(expr->getMember()),
quoteSymbol(expr->getMember().getDecl()),
quoteType(expr->getType())});
} else {
return makeQuote("Member", {quoteExpr(expr->getBase()),
quoteValue(expr->getMember()),
quoteSymbol(expr->getMember().getDecl()),
quoteType(expr->getType())});
}
}
Expr *visitNilLiteralExpr(NilLiteralExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("NilLiteral", {quoteType(expr->getType())});
}
// TODO(TF-723): Quote #selector.
UNSUPPORTED_EXPR(ObjCSelectorExpr)
// TODO(TF-723): Quote playground literals.
UNSUPPORTED_EXPR(ObjectLiteralExpr)
UNSUPPORTED_EXPR(OneWayExpr)
// NOTE: TapExpr nodes are handled during quoting of their parent nodes.
// We don't have a directly equivalent node in our trees.
UNSUPPORTED_EXPR(OpaqueValueExpr)
Expr *visitOpenExistentialExpr(OpenExistentialExpr *expr) {
Breadcrumb bc(bcs, expr);
if (auto call = dyn_cast<CallExpr>(expr->getSubExpr())) {
if (auto dot = dyn_cast<DotSyntaxCallExpr>(call->getFn())) {
if (auto ref = dyn_cast<DeclRefExpr>(dot->getFn())) {
auto member =
makeQuote("Member", {quoteExpr(expr->getExistentialValue()),
quoteValue(ref->getDeclRef()),
quoteSymbol(ref->getDecl()),
quoteType(dot->getType())});
return makeQuote(
"Call", {member, quoteLabels(call->getArgumentLabels()),
quoteArgs(call->getArg()), quoteType(call->getType())});
}
}
}
return unknownTree(expr);
}
// TODO(TF-723): Quote optional chaining.
UNSUPPORTED_EXPR(OptionalEvaluationExpr)
Expr *visitOptionalTryExpr(OptionalTryExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("OptionalTry", {quoteExpr(expr->getSubExpr()),
quoteType(expr->getType())});
}
// TODO(TF-724): Quote decls.
UNSUPPORTED_EXPR(OtherConstructorDeclRefExpr)
// NOTE: If typechecking encountered errors, there's no point in quoting
// anyway because none of that code will make it to runtime.
UNSUPPORTED_EXPR(OverloadedDeclRefExpr)
Expr *visitParenExpr(ParenExpr *expr) {
Breadcrumb bc(bcs, expr);
return quoteExpr(expr->getSubExpr());
}
Expr *visitPrefixUnaryExpr(PrefixUnaryExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Prefix",
{quoteExpr(expr->getFn()), quoteExpr(expr->getArg()),
quoteType(expr->getType())});
}
Expr *visitPostfixUnaryExpr(PostfixUnaryExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Postfix",
{quoteExpr(expr->getFn()), quoteExpr(expr->getArg()),
quoteType(expr->getType())});
}
Expr *visitQuoteLiteralExpr(QuoteLiteralExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote(
"Meta", {quoteExpr(expr->getSubExpr()), quoteType(expr->getType())});
}
// TODO(TF-724): Quote decls.
UNSUPPORTED_EXPR(RebindSelfInConstructorExpr)
// NOTE: If typechecking encountered errors, there's no point in quoting
// anyway because none of that code will make it to runtime.
UNSUPPORTED_EXPR(SequenceExpr)
Expr *visitStringLiteralExpr(StringLiteralExpr *expr) {
Breadcrumb bc(bcs, expr);
// TODO(TF-733): Figure out why this is not good enough.
// auto type = expr->getType();
auto type = ctx.getStringDecl()->getDeclaredType();
return makeQuote("StringLiteral",
{quoteString(expr->getValue()), quoteType(type)});
}
Expr *visitSubscriptExpr(SubscriptExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Subscript", {quoteExpr(expr->getBase()),
quoteSymbol(expr->getMember().getDecl()),
quoteLabels(expr->getArgumentLabels()),
quoteExprs(expr->getIndex()),
quoteType(expr->getType())});
}
Expr *visitSuperRefExpr(SuperRefExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("Super", {quoteType(expr->getType())});
}
// NOTE: TapExpr nodes are handled during quoting of their parent nodes.
// We don't have a directly equivalent node in our trees.
UNSUPPORTED_EXPR(TapExpr)
Expr *visitTryExpr(TryExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote(
"Try", {quoteExpr(expr->getSubExpr()), quoteType(expr->getType())});
}
Expr *visitTupleElementExpr(TupleElementExpr *expr) {
Breadcrumb bc(bcs, expr);
return makeQuote("TupleElement", {quoteExpr(expr->getBase()),
quoteInt(expr->getFieldNumber()),
quoteType(expr->getType())});
}
Expr *visitTupleExpr(TupleExpr *expr) {
Breadcrumb bc(bcs, expr);
// TODO(TF-731): Figure out why expr->getType() is sometimes null.
auto quotedType = expr->getType() ? quoteType(expr->getType())
: makeQuote("UnknownTree", {});
return makeQuote("Tuple", {quoteLabels(expr->getElementNames()),
quoteExprs(expr->getElements()), quotedType});
}
// NOTE: TypeExpr nodes are handled during quoting of their parent nodes.
// We don't have a directly equivalent node in our trees.
UNSUPPORTED_EXPR(TypeExpr)
Expr *visitUnquoteExpr(UnquoteExpr *expr) {
Breadcrumb bc(bcs, expr);
auto value = new (ctx)
UnresolvedDotExpr(expr->getSubExpr(), SourceLoc(),
ctx.getIdentifier("expression"), DeclNameLoc(),
/*Implicit=*/true);
return makeQuote("Unquote", {quoteExpr(expr->getSubExpr()), value,
quoteType(expr->getType())});
}
// NOTE: If typechecking encountered errors, there's no point in quoting
// anyway because none of that code will make it to runtime.
UNSUPPORTED_EXPR(UnresolvedDeclRefExpr)
UNSUPPORTED_EXPR(UnresolvedDotExpr)
UNSUPPORTED_EXPR(UnresolvedMemberExpr)
UNSUPPORTED_EXPR(UnresolvedPatternExpr)
UNSUPPORTED_EXPR(UnresolvedSpecializeExpr)
Expr *visitVarargExpansionExpr(VarargExpansionExpr *expr) {
Breadcrumb bc(bcs, expr);
if (auto exprs = dyn_cast<ArrayExpr>(expr->getSubExpr())) {
return makeQuote("Varargs", {quoteExprs(exprs->getElements()),
quoteType(expr->getType())});
} else {
return unknownTree(expr);
}
}
#define UNSUPPORTED_STMT(STMT) \
Expr *visit##STMT(STMT *stmt) { \
Breadcrumb bc(bcs, stmt); \
return unknownTree(stmt); \
}
// NOTE: BraceStmts are supported within quoteBody but not in standalone form.
UNSUPPORTED_STMT(BraceStmt)
Expr *visitBreakStmt(BreakStmt *stmt) {
Breadcrumb bc(bcs, stmt);
return makeQuote("Break", {quoteLabel(stmt->getTargetName())});
}
// TODO(TF-714): Quote patterns and trees related to pattern matching.
UNSUPPORTED_STMT(CaseStmt)
// TODO(TF-714): Quote patterns and trees related to pattern matching.
UNSUPPORTED_STMT(CatchStmt)
Expr *visitContinueStmt(ContinueStmt *stmt) {
Breadcrumb bc(bcs, stmt);
return makeQuote("Continue", {quoteLabel(stmt->getTargetName())});
}
Expr *visitDeferStmt(DeferStmt *stmt) {
Breadcrumb bc(bcs, stmt);
return makeQuote("Defer", {quoteBody(stmt->getBodyAsWritten())});
}
// TODO(TF-714): Quote patterns and trees related to pattern matching.
UNSUPPORTED_STMT(DoCatchStmt)
Expr *visitDoStmt(DoStmt *stmt) {
Breadcrumb bc(bcs, stmt);
return makeQuote("Do", {quoteLabel(stmt->getLabelInfo().Name),
quoteBody(stmt->getBody())});
}
// TODO(TF-724): Quote decls.
UNSUPPORTED_STMT(FailStmt)
// TODO(TF-714): Quote patterns and trees related to pattern matching.
UNSUPPORTED_STMT(FallthroughStmt)
Expr *visitForEachStmt(ForEachStmt *stmt) {
Breadcrumb bc(bcs, stmt);
Expr *quotedName = nullptr;
if (auto pat = dyn_cast<NamedPattern>(stmt->getPattern())) {
Breadcrumb bc(bcs, pat);
quotedName = quoteName(pat->getDecl());
}
if (!quotedName) {
quotedName = unknownName(stmt);
}
return makeQuote("For", {quoteLabel(stmt->getLabelInfo().Name), quotedName,
quoteExpr(stmt->getSequence()),
quoteBody(stmt->getBody())});
}
Expr *visitGuardStmt(GuardStmt *stmt) {
Breadcrumb bc(bcs, stmt);
return makeQuote("Guard", {quoteCond(stmt), quoteBody(stmt->getBody())});
}
Expr *visitIfStmt(IfStmt *stmt) {
Breadcrumb bc(bcs, stmt);
auto quotedElse =
stmt->getElseStmt() ? quoteBody(stmt->getElseStmt()) : quoteArray({});
return makeQuote("If",
{quoteLabel(stmt->getLabelInfo().Name), quoteCond(stmt),
quoteBody(stmt->getThenStmt()), quotedElse});
}
// NOTE: PoundAssertStmt are supported within quoteBody but not in
// standalone form.
UNSUPPORTED_STMT(PoundAssertStmt)
Expr *visitRepeatWhileStmt(RepeatWhileStmt *stmt) {
Breadcrumb bc(bcs, stmt);
return makeQuote("Repeat",
{quoteLabel(stmt->getLabelInfo().Name),
quoteBody(stmt->getBody()), quoteExpr(stmt->getCond())});
}
Expr *visitReturnStmt(ReturnStmt *stmt) {
Breadcrumb bc(bcs, stmt);
if (stmt->hasResult()) {
return makeQuote("Return", {quoteExpr(stmt->getResult())});
} else {
auto emptyResult = TupleExpr::createEmpty(ctx, SourceLoc(), SourceLoc(),
/*Implicit=*/true);
return makeQuote("Return", {quoteExpr(emptyResult)});
}
}
// TODO(TF-714): Quote patterns and trees related to pattern matching.
UNSUPPORTED_STMT(SwitchStmt)
Expr *visitThrowStmt(ThrowStmt *stmt) {
Breadcrumb bc(bcs, stmt);
return makeQuote("Throw", {quoteExpr(stmt->getSubExpr())});
}
Expr *visitWhileStmt(WhileStmt *stmt) {
Breadcrumb bc(bcs, stmt);
return makeQuote("While", {quoteLabel(stmt->getLabelInfo().Name),
quoteCond(stmt), quoteBody(stmt->getBody())});
}
// NOTE: Doesn't look like this is an official feature so we won't be
// supporting it for now.
UNSUPPORTED_STMT(YieldStmt)
#undef UNSUPPORTED_STMT
#define UNSUPPORTED_DECL(DECL) \
Expr *visit##DECL(DECL *decl) { \
Breadcrumb bc(bcs, decl); \
return unknownTree(decl); \
}
// TODO(TF-724): Quote decls.
UNSUPPORTED_DECL(AccessorDecl)
UNSUPPORTED_DECL(AssociatedTypeDecl)
UNSUPPORTED_DECL(ConstructorDecl)
UNSUPPORTED_DECL(ClassDecl)
UNSUPPORTED_DECL(DestructorDecl)
UNSUPPORTED_DECL(EnumCaseDecl)
UNSUPPORTED_DECL(EnumDecl)
UNSUPPORTED_DECL(EnumElementDecl)
UNSUPPORTED_DECL(ExtensionDecl)
Expr *visitFuncDecl(FuncDecl *decl) {
return makeQuote("Function",
{quoteName(decl), quoteParams(decl->getParameters()),
quoteBody(decl->getBody())});
}
// TODO(TF-724): Quote decls.
UNSUPPORTED_DECL(GenericTypeParamDecl)
// NOTE: Doesn't have a representation in quotes.
// We simply take active elements and use them instead of this decl.
UNSUPPORTED_DECL(IfConfigDecl)
// TODO(TF-724): Quote decls.
UNSUPPORTED_DECL(ImportDecl)
UNSUPPORTED_DECL(MissingMemberDecl)
UNSUPPORTED_DECL(ModuleDecl)
Expr *visitParamDecl(ParamDecl *decl) {
Breadcrumb bc(bcs, decl);
return makeQuote("Parameter",
{quoteLabel(decl->getArgumentName()), quoteName(decl)});
}
Expr *visitPatternBindingDecl(PatternBindingDecl *decl) {
Breadcrumb bc(bcs, decl);
if (auto var = decl->getSingleVar()) {
Breadcrumb bc(bcs, var);
if (var->isLet()) {
return makeQuote("Let", {quoteName(var), quoteExpr(decl->getInit(0))});
} else {
return makeQuote("Var", {quoteName(var), quoteExpr(decl->getInit(0))});
}
} else {
// TODO(TF-714): Quote patterns and trees related to pattern
// matching.
return unknownTree(decl);
}
}
// NOTE: Doesn't have a representation in quotes since this language construct
// belongs to the compilation stage that precedes quotes.
UNSUPPORTED_DECL(PoundDiagnosticDecl)
// TODO(TF-724): Quote decls.
UNSUPPORTED_DECL(PrecedenceGroupDecl)
UNSUPPORTED_DECL(ProtocolDecl)
UNSUPPORTED_DECL(OpaqueTypeDecl)
UNSUPPORTED_DECL(OperatorDecl)
UNSUPPORTED_DECL(StructDecl)
UNSUPPORTED_DECL(SubscriptDecl)
UNSUPPORTED_DECL(TopLevelCodeDecl)
UNSUPPORTED_DECL(TypeAliasDecl)
UNSUPPORTED_DECL(VarDecl)
#undef UNSUPPORTED_DECL
private:
Expr *quoteArgs(Expr *arg) {
Breadcrumb bc(bcs, arg);
if (auto args = dyn_cast<ParenExpr>(arg)) {
return quoteExprs({args->getSubExpr()});
} else if (auto args = dyn_cast<TupleExpr>(arg)) {
return quoteExprs(args->getElements());
} else {
return quoteArray(unknownTree(arg));
}
}
Expr *quoteBody(Stmt *stmt) {
Breadcrumb bc(bcs, stmt);
if (auto body = dyn_cast<BraceStmt>(stmt)) {
SmallVector<Expr *, 4> quotedBody;
std::function<void(ASTNode)> handleNode = [&](ASTNode node) {
if (auto expr = node.dyn_cast<Expr *>()) {
quotedBody.push_back(quoteExpr(expr));
return;
}
if (auto stmt = node.dyn_cast<Stmt *>()) {
if (isa<PoundAssertStmt>(stmt)) {
return;
}
quotedBody.push_back(quoteStmt(stmt));
return;
}
auto decl = node.get<Decl *>();
if (auto poundIf = dyn_cast<IfConfigDecl>(decl)) {
for (auto elem : poundIf->getActiveClauseElements()) {
handleNode(elem);
}
return;
}
if (isa<PoundDiagnosticDecl>(decl)) {
return;
}
if (isa<VarDecl>(decl)) {
return;
}
quotedBody.push_back(quoteDecl(decl));
};
for (auto elem : body->getElements()) {
handleNode(elem);
}
return quoteArray(quotedBody);
} else {
return quoteArray({quoteStmt(stmt)});
}
}
template <typename T> Expr *quoteCond(T *stmt) {
SmallVector<Expr *, 4> quotedCond;
for (auto element : stmt->getCond()) {
Breadcrumb bc(bcs, &element);
Expr *quotedElement;
switch (element.getKind()) {
case StmtConditionElement::ConditionKind::CK_Boolean:
quotedElement = quoteExpr(element.getBoolean());
break;
case StmtConditionElement::ConditionKind::CK_PatternBinding:
// TODO(TF-714): Quote patterns and trees related to pattern
// matching.
quotedElement = unknownTree(stmt);
break;
case StmtConditionElement::ConditionKind::CK_Availability:
// TODO(TF-723): Quote #available.
quotedElement = unknownTree(stmt);
break;
}
quotedCond.push_back(quotedElement);
}
return quoteArray(quotedCond);
}
Expr *quoteDecl(Decl *decl) { return visit(decl); }
Expr *quoteExpr(Expr *expr) { return visit(expr); }
Expr *quoteExprs(ArrayRef<Expr *> exprs) {
SmallVector<Expr *, 4> quotedExprs;
for (auto expr : exprs) {
quotedExprs.push_back(quoteExpr(expr));
}
return quoteArray(quotedExprs);
}
Expr *quoteLabel(Identifier id) {
if (id.empty()) {
return quoteNil();
} else {
return quoteString(id.str());
}
}
Expr *quoteLabels(ArrayRef<Identifier> ids) {
SmallVector<Expr *, 4> quotedLabels;
for (auto id : ids) {
quotedLabels.push_back(quoteLabel(id));
}
return quoteArray(quotedLabels);
}
Expr *quoteName(ValueDecl *decl) {
Type type;
if (auto decl2 = dyn_cast<FuncDecl>(decl)) {
SmallVector<AnyFunctionType::Param, 4> paramTypes;
for (auto param : decl2->getParameters()->getArray()) {
auto flags = ParameterTypeFlags();
if (param->isInOut()) {
flags = flags.withInOut(true);
}
auto paramType =
AnyFunctionType::Param(param->getType(), Identifier(), flags);
paramTypes.push_back(paramType);
}
auto retType = decl2->getBodyResultTypeLoc().getTypeRepr()
? decl2->getBodyResultTypeLoc().getType()
: decl2->getResultInterfaceType();
if (retType) {
type = FunctionType::get(paramTypes, retType);
}
} else if (auto decl2 = dyn_cast<VarDecl>(decl)) {
type = decl2->getType();
if (auto decl2 = dyn_cast<ParamDecl>(decl)) {
if (decl2->isInOut()) {
type = InOutType::get(type);
}
}
}
Expr *quotedType = type ? quoteType(type) : unknownTree(decl);
return makeQuote("Name", {quoteString(decl->getBaseName().userFacingName()),
quoteSymbol(decl), quotedType});
}
Expr *quoteNil() {
return new (ctx) NilLiteralExpr(SourceLoc(), /*Implicit=*/true);
}
Expr *quoteParams(ParameterList *params) {
SmallVector<Expr *, 4> quotedParams;
for (auto param : params->getArray()) {
quotedParams.push_back(quoteDecl(param));
}
return quoteArray(quotedParams);
}
Expr *quoteStmt(Stmt *stmt) { return visit(stmt); }
Expr *quoteType(Type type) {
return type ? typeQuoter.visit(type) : unknownTree(type);
}
Expr *quoteValue(ConcreteDeclRef ref) {
// TODO(TF-740): Obtain value exactly as written by the programmer.
// I'm currently not sure how to do that since DeclRefExpr doesn't have
// a correct source range.
if (auto ctor = dyn_cast<ConstructorDecl>(ref.getDecl())) {
auto type = ctor->getResultInterfaceType();
if (auto nomType = type->getAs<NominalType>()) {
return quoteString(nomType->getDecl()->getBaseName().userFacingName());
}
}
return quoteString(ref.getDecl()->getBaseName().userFacingName());
}
// TODO(TF-735): Implement ExpressibleByQuoteLiteral.
Expr *makeQuote(const char *name, ArrayRef<Expr *> quotedSubnodes) {
auto nodeInit = new (ctx) UnresolvedDeclRefExpr(
ctx.getIdentifier(name), DeclRefKind::Ordinary, DeclNameLoc());
return CallExpr::createImplicit(ctx, nodeInit, quotedSubnodes, {});
}
};
} // end anonymous namespace
Expr *TypeChecker::quoteExpr(Expr *expr, DeclContext *dc) {
assert(expr->getType());
Breadcrumbs bcs;
ASTQuoter astQuoter(*this, bcs);
Expr *quotedExpr = astQuoter.visit(expr);
if (!quotedExpr) {
return nullptr;
}
auto quoteType = getTypeOfQuoteExpr(expr->getType(), expr->getLoc());
if (!quoteType) {
return nullptr;
}
auto quoteClassType = quoteType->getAs<BoundGenericClassType>();
if (!quoteClassType) {
return nullptr;
}
auto quoteRef =
new (Context) UnresolvedDeclRefExpr(quoteClassType->getDecl()->getName(),
DeclRefKind::Ordinary, DeclNameLoc());
SmallVector<TypeLoc, 4> quoteTargs;
for (auto targ : quoteClassType->getGenericArgs()) {
auto targRepr = new (Context) FixedTypeRepr(targ, SourceLoc());
quoteTargs.push_back(TypeLoc(targRepr));
}
auto quoteInit = UnresolvedSpecializeExpr::create(
Context, quoteRef, SourceLoc(), quoteTargs, SourceLoc());
quoteInit->setImplicit();
Expr *quoteCall =
CallExpr::createImplicit(Context, quoteInit, {quotedExpr}, {});
// TODO(TF-727): Improve error reporting when quoting fails.
if (!typeCheckExpression(quoteCall, dc)) {
return nullptr;
}
// TODO(TF-734): Get to the bottom of why we need this workaround.
if (auto call2 = dyn_cast<CallExpr>(quoteCall)) {
if (auto init2 = dyn_cast<ConstructorRefCallExpr>(call2->getFn())) {
init2->getBase()->setImplicit();
return quoteCall;
}
}
return nullptr;
}
Type TypeChecker::getTypeOfQuoteExpr(Type exprType, SourceLoc loc) {
assert(exprType);
if (!Context.getQuoteModule()) {
diagnose(loc, diag::quote_literal_no_quote_module);
return Type();
}
if (auto fnExprType = exprType->getAs<FunctionType>()) {
auto n = fnExprType->getParams().size();
auto quoteClass = Context.getFunctionQuoteDecl(n);
if (!quoteClass) {
diagnose(loc, diag::quote_literal_no_function_quote_class, n);
return Type();
}
SmallVector<Type, 4> typeArgs;
for (auto param : fnExprType->getParams()) {
auto paramType = param.getPlainType();
if (param.isInOut()) {
paramType = paramType->wrapInPointer(PTK_UnsafeMutablePointer);
}
typeArgs.push_back(paramType);
}
typeArgs.push_back(fnExprType->getResult());
return BoundGenericClassType::get(quoteClass, Type(), typeArgs);
} else {
auto quoteClass = Context.getQuoteDecl();
if (!quoteClass) {
diagnose(loc, diag::quote_literal_no_quote_class);
return Type();
}
if (auto lvalueExprType = exprType->getAs<LValueType>()) {
exprType = lvalueExprType->getObjectType();
}
return BoundGenericClassType::get(quoteClass, Type(), exprType);
}
}
Type TypeChecker::getTypeOfUnquoteExpr(Type exprType, SourceLoc loc) {
assert(exprType);
if (auto genericType = exprType->getAs<BoundGenericClassType>()) {
auto classDecl = genericType->getDecl();
auto typeArgs = genericType->getGenericArgs();
if (classDecl == Context.getQuoteDecl()) {
return typeArgs[0];
} else if (classDecl == Context.getFunctionQuoteDecl(typeArgs.size() - 1)) {
SmallVector<AnyFunctionType::Param, 4> paramTypes;
for (unsigned i = 0; i < typeArgs.size() - 1; ++i) {
auto typeArg = typeArgs[i];
auto flags = ParameterTypeFlags();
if (auto genericTypeArg = typeArg->getAs<BoundGenericClassType>()) {
if (genericTypeArg->getDecl() ==
Context.getUnsafeMutablePointerDecl()) {
flags = flags.withInOut(true);
}
}
auto paramType = AnyFunctionType::Param(typeArg, Identifier(), flags);
paramTypes.push_back(paramType);
}
return FunctionType::get(paramTypes, typeArgs[typeArgs.size() - 1]);
} else {
diagnose(loc, diag::unquote_wrong_type);
return Type();
}
} else {
diagnose(loc, diag::unquote_wrong_type);
return Type();
}
}
Expr *TypeChecker::quoteDecl(Decl *decl, DeclContext *dc) {
Breadcrumbs bcs;
ASTQuoter astQuoter(*this, bcs);
Expr *quotedDecl = astQuoter.visit(decl);
if (!quotedDecl) {
return nullptr;
}
// TODO(TF-727): Improve error reporting when quoting fails.
if (!typeCheckExpression(quotedDecl, dc)) {
return nullptr;
}
return quotedDecl;
}
Type TypeChecker::getTypeOfQuoteDecl(SourceLoc loc) {
if (!Context.getQuoteModule()) {
diagnose(loc, diag::quote_literal_no_quote_module);
return Type();
}
auto treeProto = Context.getTreeDecl();
if (!treeProto) {
diagnose(loc, diag::quote_literal_no_tree_proto);
return Type();
}
return treeProto->getDeclaredType();
}