Skip to content

Convert DictionaryExpr to not use tc.callWitness() or generate a SemanticExpr. #25408

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 1 commit into from
Jun 17, 2019
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
7 changes: 2 additions & 5 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2128,8 +2128,6 @@ class CollectionExpr : public Expr {
SourceLoc RBracketLoc;
ConcreteDeclRef Initializer;

Expr *SemanticExpr = nullptr;

/// Retrieve the intrusive pointer storage from the subtype
Expr *const *getTrailingObjectsPointer() const;
Expr **getTrailingObjectsPointer() {
Expand Down Expand Up @@ -2194,9 +2192,6 @@ class CollectionExpr : public Expr {
SourceRange getSourceRange() const {
return SourceRange(LBracketLoc, RBracketLoc);
}

Expr *getSemanticExpr() const { return SemanticExpr; }
void setSemanticExpr(Expr *e) { SemanticExpr = e; }

static bool classof(const Expr *e) {
return e->getKind() >= ExprKind::First_CollectionExpr &&
Expand Down Expand Up @@ -2274,6 +2269,8 @@ class DictionaryExpr final : public CollectionExpr,
static bool classof(const Expr *e) {
return e->getKind() == ExprKind::Dictionary;
}

Type getElementType();
};

/// Subscripting expressions like a[i] that refer to an element within a
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2127,16 +2127,16 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
OS << '\n';
printRec(elt);
}
printSemanticExpr(E->getSemanticExpr());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void visitDictionaryExpr(DictionaryExpr *E) {
printCommon(E, "dictionary_expr");
PrintWithColorRAII(OS, LiteralValueColor) << " initializer=";
E->getInitializer().dump(PrintWithColorRAII(OS, LiteralValueColor).getOS());
for (auto elt : E->getElements()) {
OS << '\n';
printRec(elt);
}
printSemanticExpr(E->getSemanticExpr());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void visitSubscriptExpr(SubscriptExpr *E) {
Expand Down
2 changes: 0 additions & 2 deletions lib/AST/ASTWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,8 +525,6 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
}

Expr *visitCollectionExpr(CollectionExpr *E) {
HANDLE_SEMANTIC_EXPR(E);

for (auto &elt : E->getElements())
if (Expr *Sub = doIt(elt))
elt = Sub;
Expand Down
13 changes: 13 additions & 0 deletions lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,19 @@ Type ArrayExpr::getElementType() {
.subst(init.getSubstitutions());
}

Type DictionaryExpr::getElementType() {
auto init = getInitializer();
if (!init)
return Type();

auto *decl = cast<ConstructorDecl>(init.getDecl());
return decl->getMethodInterfaceType()
->getAs<AnyFunctionType>()
->getParams()[0]
.getPlainType()
.subst(init.getSubstitutions());
}

DictionaryExpr *DictionaryExpr::create(ASTContext &C, SourceLoc LBracketLoc,
ArrayRef<Expr*> Elements,
ArrayRef<SourceLoc> CommaLocs,
Expand Down
16 changes: 8 additions & 8 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,7 @@ namespace {
RValue visitKeyPathExpr(KeyPathExpr *E, SGFContext C);
RValue visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E,
SGFContext C);
RValue visitArrayExpr(ArrayExpr *E, SGFContext C);
RValue visitDictionaryExpr(DictionaryExpr *E, SGFContext C);
RValue visitCollectionExpr(CollectionExpr *E, SGFContext C);
RValue visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E,
SGFContext C);
RValue visitInjectIntoOptionalExpr(InjectIntoOptionalExpr *E, SGFContext C);
Expand Down Expand Up @@ -3671,15 +3670,20 @@ visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, SGFContext C) {
llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch.");
}

RValue RValueEmitter::visitArrayExpr(ArrayExpr *E, SGFContext C) {
RValue RValueEmitter::visitCollectionExpr(CollectionExpr *E, SGFContext C) {
auto loc = SILLocation(E);
ArgumentScope scope(SGF, loc);

// CSApply builds ArrayExprs without an initializer for the trivial case
// of emitting varargs.
CanType arrayType, elementType;
if (E->getInitializer()) {
elementType = E->getElementType()->getCanonicalType();
if (auto *arrayExpr = dyn_cast<ArrayExpr>(E)) {
elementType = arrayExpr->getElementType()->getCanonicalType();
} else {
auto *dictionaryExpr = cast<DictionaryExpr>(E);
elementType = dictionaryExpr->getElementType()->getCanonicalType();
}
arrayType = ArraySliceType::get(elementType)->getCanonicalType();
} else {
arrayType = E->getType()->getCanonicalType();
Expand Down Expand Up @@ -3742,10 +3746,6 @@ RValue RValueEmitter::visitArrayExpr(ArrayExpr *E, SGFContext C) {
loc, E->getInitializer(), std::move(args), E->getType(), C);
}

RValue RValueEmitter::visitDictionaryExpr(DictionaryExpr *E, SGFContext C) {
return visit(E->getSemanticExpr(), C);
}

/// Flattens one level of optional from a nested optional value.
static ManagedValue flattenOptional(SILGenFunction &SGF, SILLocation loc,
ManagedValue optVal) {
Expand Down
63 changes: 9 additions & 54 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2929,65 +2929,20 @@ namespace {
if (!conformance)
return nullptr;

// Call the witness that builds the dictionary literal.
// FIXME: callWitness() may end up re-doing some work we already did
// to convert the dictionary literal elements to the (key, value) tuple.
// It would be nicer to re-use them.
// FIXME: Cache the name.
// FIXME: This location info is bogus.
Expr *typeRef = TypeExpr::createImplicitHack(expr->getLoc(), dictionaryTy,
tc.Context);
cs.cacheExprTypes(typeRef);

DeclName name(tc.Context, DeclBaseName::createConstructor(),
{ tc.Context.Id_dictionaryLiteral });

// Restructure the argument to provide the appropriate labels in the
// tuple.
SmallVector<TupleTypeElt, 4> typeElements;
SmallVector<Identifier, 4> names;
bool first = true;
for (auto elt : expr->getElements()) {
if (first) {
typeElements.push_back(TupleTypeElt(cs.getType(elt),
tc.Context.Id_dictionaryLiteral));
names.push_back(tc.Context.Id_dictionaryLiteral);

first = false;
continue;
}

typeElements.push_back(cs.getType(elt));
names.push_back(Identifier());
}

Type argType = TupleType::get(typeElements, tc.Context);
assert(isa<TupleType>(argType.getPointer()));

Expr *arg =
TupleExpr::create(tc.Context, expr->getLBracketLoc(),
expr->getElements(),
names,
{ },
expr->getRBracketLoc(),
/*HasTrailingClosure=*/false,
/*Implicit=*/true,
argType);

cs.cacheExprTypes(arg);

cs.setExprTypes(typeRef);
cs.setExprTypes(arg);

Expr *result = tc.callWitness(typeRef, dc, dictionaryProto,
*conformance, name, arg,
diag::dictionary_protocol_broken);
if (!result)
ConcreteDeclRef witness =
conformance->getWitnessByName(dictionaryTy->getRValueType(), name);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;
expr->setInitializer(witness);

cs.cacheExprTypes(result);
auto elementType = expr->getElementType();
for (auto &element : expr->getElements()) {
element = coerceToType(element, elementType,
cs.getConstraintLocator(element));
}

expr->setSemanticExpr(result);
return expr;
}

Expand Down
17 changes: 0 additions & 17 deletions lib/Sema/CSDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,6 @@ namespace {
llvm::DenseMap<Pattern*, Type> PatternTypes;
llvm::DenseMap<ParamDecl*, Type> ParamDeclTypes;
llvm::DenseMap<ParamDecl*, Type> ParamDeclInterfaceTypes;
llvm::DenseMap<CollectionExpr*, Expr*> CollectionSemanticExprs;
llvm::DenseSet<ValueDecl*> PossiblyInvalidDecls;
ExprTypeSaverAndEraser(const ExprTypeSaverAndEraser&) = delete;
void operator=(const ExprTypeSaverAndEraser&) = delete;
Expand Down Expand Up @@ -1340,15 +1339,6 @@ namespace {
P->setInvalid(false);
}

// If we have a CollectionExpr with a type checked SemanticExpr,
// remove it so we can recalculate a new semantic form.
if (auto *CE = dyn_cast<CollectionExpr>(expr)) {
if (auto SE = CE->getSemanticExpr()) {
TS->CollectionSemanticExprs[CE] = SE;
CE->setSemanticExpr(nullptr);
}
}

expr->setType(nullptr);

return { true, expr };
Expand Down Expand Up @@ -1403,9 +1393,6 @@ namespace {
paramDeclIfaceElt.first->setInterfaceType(paramDeclIfaceElt.second->getInOutObjectType());
}

for (auto CSE : CollectionSemanticExprs)
CSE.first->setSemanticExpr(CSE.second);

if (!PossiblyInvalidDecls.empty())
for (auto D : PossiblyInvalidDecls)
if (D->hasInterfaceType())
Expand All @@ -1426,10 +1413,6 @@ namespace {
// we go digging through failed constraints, and expect their locators to
// still be meaningful.
~ExprTypeSaverAndEraser() {
for (auto CSE : CollectionSemanticExprs)
Copy link
Contributor

Choose a reason for hiding this comment

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

I love that ExprTypeSaverAndEraser becomes simpler as well (ideally it wouldn't exist; there's a lot of refactoring before we can do that though!)

if (!CSE.first->getType())
CSE.first->setSemanticExpr(CSE.second);

for (auto exprElt : ExprTypes)
if (!exprElt.first->getType())
exprElt.first->setType(exprElt.second);
Expand Down
4 changes: 1 addition & 3 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3317,9 +3317,7 @@ namespace {
}

// Remove any semantic expression injected by typechecking.
if (auto CE = dyn_cast<CollectionExpr>(expr)) {
CE->setSemanticExpr(nullptr);
} else if (auto ISLE = dyn_cast<InterpolatedStringLiteralExpr>(expr)) {
if (auto ISLE = dyn_cast<InterpolatedStringLiteralExpr>(expr)) {
ISLE->setSemanticExpr(nullptr);
} else if (auto OLE = dyn_cast<ObjectLiteralExpr>(expr)) {
OLE->setSemanticExpr(nullptr);
Expand Down
33 changes: 33 additions & 0 deletions test/SILGen/literals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,39 @@ func throwingElement<T : FooProtocol>() throws -> [T] {
return try [makeBasic(), makeThrowing()]
}

class TakesDictionaryLiteral<Key, Value> : ExpressibleByDictionaryLiteral {
required init(dictionaryLiteral elements: (Key, Value)...) {}
}

// CHECK-LABEL: sil hidden [ossa] @$s8literals23returnsCustomDictionaryAA05TakesD7LiteralCyS2iGyF : $@convention(thin) () -> @owned TakesDictionaryLiteral<Int, Int> {
// CHECK: [[TMP:%.*]] = apply %2(%0, %1) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
// CHECK: [[ARRAY_LENGTH:%.*]] = integer_literal $Builtin.Word, 2
// CHECK: // function_ref _allocateUninitializedArray<A>(_:)
// CHECK: [[ALLOCATE_VARARGS:%.*]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
// CHECK: [[ARR_TMP:%.*]] = apply [[ALLOCATE_VARARGS]]<(Int, Int)>([[ARRAY_LENGTH]])
// CHECK: ([[ARR:%.*]], [[ADDRESS:%.*]]) = destructure_tuple [[ARR_TMP]]
// CHECK: [[TUPLE_ADDR:%.*]] = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*(Int, Int)
// CHECK: [[KEY_ADDR:%.*]] = tuple_element_addr [[TUPLE_ADDR]] : $*(Int, Int), 0
// CHECK: [[VALUE_ADDR:%.*]] = tuple_element_addr [[TUPLE_ADDR]] : $*(Int, Int), 1
// CHECK: store [[TMP]] to [trivial] [[KEY_ADDR]] : $*Int
// CHECK: store [[TMP]] to [trivial] [[VALUE_ADDR]] : $*Int
// CHECK: [[IDX1:%.*]] = integer_literal $Builtin.Word, 1
// CHECK: [[TUPLE_ADDR1:%.*]] = index_addr [[TUPLE_ADDR]] : $*(Int, Int), [[IDX1]] : $Builtin.Word
// CHECK: [[KEY_ADDR:%.*]] = tuple_element_addr [[TUPLE_ADDR1]] : $*(Int, Int), 0
// CHECK: [[VALUE_ADDR:%.*]] = tuple_element_addr [[TUPLE_ADDR1]] : $*(Int, Int), 1
// CHECK: store [[TMP]] to [trivial] [[KEY_ADDR]] : $*Int
// CHECK: store [[TMP]] to [trivial] [[VALUE_ADDR]] : $*Int
// CHECK: [[METATYPE:%.*]] = metatype $@thick TakesDictionaryLiteral<Int, Int>.Type
// CHECK: [[CTOR:%.*]] = class_method [[METATYPE]] : $@thick TakesDictionaryLiteral<Int, Int>.Type, #TakesDictionaryLiteral.init!allocator.1 : <Key, Value> (TakesDictionaryLiteral<Key, Value>.Type) -> ((Key, Value)...) -> TakesDictionaryLiteral<Key, Value>, $@convention(method) <τ_0_0, τ_0_1> (@owned Array<(τ_0_0, τ_0_1)>, @thick TakesDictionaryLiteral<τ_0_0, τ_0_1>.Type) -> @owned TakesDictionaryLiteral<τ_0_0, τ_0_1>
// CHECK: [[RESULT:%.*]] = apply [[CTOR]]<Int, Int>(%8, %21)
// CHECK: return [[RESULT]]

func returnsCustomDictionary() -> TakesDictionaryLiteral<Int, Int> {
// Use temporary to simplify generated_sil
let tmp = 77
return [tmp: tmp, tmp : tmp]
}

struct Color: _ExpressibleByColorLiteral {
init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float) {}
}
Expand Down
12 changes: 5 additions & 7 deletions test/SILGen/sil_locations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -259,17 +259,15 @@ func tuple_element(_ x: (Int, Float)) {
}

func containers() -> ([Int], Dictionary<String, Int>) {
return ([1, 2, 3], ["Ankeny": 1, "Burnside": 2, "Couch": 3])
return ([1, 2, 3], ["Ankeny": 101, "Burnside": 102, "Couch": 103])
// CHECK-LABEL: sil hidden [ossa] @$s13sil_locations10containers{{[_0-9a-zA-Z]*}}F
// CHECK: apply {{%.*}}<(String, Int)>({{%.*}}), loc "{{.*}}":[[@LINE-2]]:23

// CHECK: string_literal utf8 "Ankeny", loc "{{.*}}":[[@LINE-4]]:23
// CHECK: string_literal utf8 "Ankeny", loc "{{.*}}":[[@LINE-3]]:23

// CHECK: integer_literal $Builtin.IntLiteral, 1, loc "{{.*}}":[[@LINE-6]]:33
// CHECK: integer_literal $Builtin.IntLiteral, 2, loc "{{.*}}":[[@LINE-7]]:48
// CHECK: integer_literal $Builtin.IntLiteral, 101, loc "{{.*}}":[[@LINE-5]]:33
// CHECK: integer_literal $Builtin.IntLiteral, 102, loc "{{.*}}":[[@LINE-6]]:50



// CHECK: apply {{%.*}}<String, Int>({{%.*}}, {{%.*}}) : {{.*}}, loc "{{.*}}":[[@LINE-8]]:22
}


Expand Down