Files
swift-mirror/lib/SILGen/ArgumentSource.cpp
Slava Pestov e1f0f02480 SILGen: Three-parameter re-abstraction thunks
Right now, re-abstraction thunks are set up to convert values
as follows, where L is type lowering:

- OrigToSubst: L(origType, substType) -> L(substType)
- SubstToOrig: L(substType) -> L(origType, substType)

This assumes there's no AST-level type conversion, because
when we visit a type in contravariant position, we flip the
direction of the transform but we're still converting *to*
substType -- which will now equal to the type of the input,
not the type of the expected result!

This caused several problems:

- VTable thunk generation had a bunch of special logic to
  compute a substOverrideType, and wrap the thunk result
  in an optional, duplicating work done in the transform

- Witness thunk generation similarly had to handle the case
  of upcasting to a base class to call the witness, and
  casting the result of materializeForSet back to the right
  type for properties defined on the base.

  Now the materializeForSet cast sequence is a bit longer,
  we unpack the returned tuple and do a convert_function
  on the function, then pack it again -- before we would
  unchecked_ref_cast the tuple, which is technically
  incorrect since the tuple is not a ref, but IRGen didn't
  seem to care...

To handle the conversions correctly, we add a third AST type
parameter to a transform, named inputType. Now, transforms
perform these conversions:

- OrigToSubst: L(origType, inputType) -> L(substType)
- SubstToOrig: L(inputType) -> L(origType, substType)

When we flip the direction of the transform while visiting
types in contravariant position, we also swap substType with
inputType.

Note that this is similar to how bridging thunks work, for
the same reason -- bridging thunks convert between AST types.

This is mostly just a nice cleanup that fixes some obscure
corner cases for now, but this functionality will be used
in a subsequent patch.

Swift SVN r31486
2015-08-26 09:15:29 +00:00

171 lines
5.9 KiB
C++

//===--- ArgumentSource.cpp - Latent value representation -------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// A structure for holding a r-value or l-value
//
//===----------------------------------------------------------------------===//
#include "ArgumentSource.h"
#include "Initialization.h"
using namespace swift;
using namespace Lowering;
RValue &ArgumentSource::forceAndPeekRValue(SILGenFunction &gen) & {
if (isRValue()) {
return peekRValue();
}
auto expr = asKnownExpr();
StoredKind = Kind::RValue;
new (&Storage.TheRV.Value) RValue(gen.emitRValue(expr));
Storage.TheRV.Loc = expr;
return Storage.TheRV.Value;
}
RValue &ArgumentSource::peekRValue() & {
assert(isRValue() && "Undefined behavior to call this method without the "
"ArgumentSource actually being an RValue");
return Storage.TheRV.Value;
}
void ArgumentSource::rewriteType(CanType newType) & {
assert(!isLValue());
if (isRValue()) {
Storage.TheRV.Value.rewriteType(newType);
} else {
Expr *expr = Storage.TheExpr;
if (expr->getType()->isEqual(newType)) return;
llvm_unreachable("unimplemented! hope it doesn't happen");
}
}
RValue ArgumentSource::getAsRValue(SILGenFunction &gen, SGFContext C) && {
assert(!isLValue());
if (isRValue())
return std::move(*this).asKnownRValue();
return gen.emitRValue(std::move(*this).asKnownExpr(), C);
}
ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &gen,
SGFContext C) && {
if (isRValue()) {
auto loc = getKnownRValueLocation();
return std::move(*this).asKnownRValue().getAsSingleValue(gen, loc);
}
if (isLValue()) {
auto loc = getKnownLValueLocation();
return gen.emitAddressOfLValue(loc, std::move(*this).asKnownLValue(),
AccessKind::ReadWrite);
}
auto e = std::move(*this).asKnownExpr();
if (e->getType()->is<InOutType>()) {
return gen.emitAddressOfLValue(e, gen.emitLValue(e, AccessKind::ReadWrite),
AccessKind::ReadWrite);
} else {
return gen.emitRValueAsSingleValue(e, C);
}
}
void ArgumentSource::forwardInto(SILGenFunction &gen, Initialization *dest) && {
assert(!isLValue());
if (isRValue()) {
auto loc = getKnownRValueLocation();
return std::move(*this).asKnownRValue().forwardInto(gen, dest, loc);
}
auto e = std::move(*this).asKnownExpr();
return gen.emitExprInto(e, dest);
}
ManagedValue ArgumentSource::materialize(SILGenFunction &gen) && {
assert(!isLValue());
if (isRValue()) {
auto loc = getKnownRValueLocation();
return std::move(*this).asKnownRValue().materialize(gen, loc);
}
auto expr = std::move(*this).asKnownExpr();
auto temp = gen.emitTemporary(expr, gen.getTypeLowering(expr->getType()));
gen.emitExprInto(expr, temp.get());
return temp->getManagedAddress();
}
ManagedValue ArgumentSource::materialize(SILGenFunction &SGF,
AbstractionPattern origFormalType,
SILType destType) && {
auto substFormalType = CanType(getSubstType()->getInOutObjectType());
assert(!destType || destType.getObjectType() ==
SGF.SGM.Types.getLoweredType(origFormalType,
substFormalType).getObjectType());
// Fast path: if the types match exactly, no abstraction difference
// is possible and we can just materialize as normal.
if (origFormalType.isExactType(substFormalType))
return std::move(*this).materialize(SGF);
auto &destTL =
(destType ? SGF.getTypeLowering(destType)
: SGF.getTypeLowering(origFormalType, substFormalType));
if (!destType) destType = destTL.getLoweredType();
// If there's no abstraction difference, we can just materialize as normal.
if (destTL.getLoweredType() == SGF.getLoweredType(substFormalType)) {
return std::move(*this).materialize(SGF);
}
// Emit a temporary at the given address.
auto temp = SGF.emitTemporary(getLocation(), destTL);
// Forward into it.
std::move(*this).forwardInto(SGF, origFormalType, temp.get(), destTL);
return temp->getManagedAddress();
}
void ArgumentSource::forwardInto(SILGenFunction &SGF,
AbstractionPattern origFormalType,
Initialization *dest,
const TypeLowering &destTL) && {
auto substFormalType = getSubstType();
assert(destTL.getLoweredType() ==
SGF.getLoweredType(origFormalType, substFormalType));
// If there are no abstraction changes, we can just forward
// normally.
if (origFormalType.isExactType(substFormalType) ||
destTL.getLoweredType() == SGF.getLoweredType(substFormalType)) {
std::move(*this).forwardInto(SGF, dest);
return;
}
// Otherwise, emit as a single independent value.
SILLocation loc = getLocation();
ManagedValue inputValue = std::move(*this).getAsSingleValue(SGF);
// Reabstract.
ManagedValue outputValue =
SGF.emitSubstToOrigValue(loc, inputValue, origFormalType,
substFormalType, substFormalType,
SGFContext(dest));
if (outputValue.isInContext()) return;
// Use RValue's forward-into-initialization code. We have to lie to
// RValue about the formal type (by using the lowered type) because
// we're emitting into an abstracted value, which RValue doesn't
// really handle.
auto substLoweredType = destTL.getLoweredType().getSwiftRValueType();
RValue(SGF, loc, substLoweredType, outputValue).forwardInto(SGF, dest, loc);
}