SILGen: add RValue emission for BorrowExpr

This commit is contained in:
Kavon Farvardin
2025-11-07 11:52:35 -08:00
parent e39a31a05f
commit 314093f426
6 changed files with 54 additions and 6 deletions

View File

@@ -2508,6 +2508,24 @@ public:
verifyCheckedBase(E);
}
void verifyChecked(BorrowExpr *E) {
PrettyStackTraceExpr debugStack(Ctx, "verifying BorrowExpr", E);
auto toType = E->getType();
auto fromType = E->getSubExpr()->getType();
// FIXME: doesStorageProduceLValue should not return false for a 'let',
// so that you can borrow from it.
if (!fromType->hasLValueType())
error("borrow source must be an l-value", E);
// Result type can be either l-value or r-value.
// Ensure underlying type matches.
if (fromType->getRValueType()->getCanonicalType() !=
toType->getRValueType()->getCanonicalType())
error("borrow should not be performing a cast", E);
}
void verifyChecked(ABISafeConversionExpr *E) {
PrettyStackTraceExpr debugStack(Ctx, "verify ABISafeConversionExpr", E);

View File

@@ -468,6 +468,7 @@ namespace {
RValue visitStringLiteralExpr(StringLiteralExpr *E, SGFContext C);
RValue visitLoadExpr(LoadExpr *E, SGFContext C);
RValue visitBorrowExpr(BorrowExpr *E, SGFContext C);
RValue visitDerivedToBaseExpr(DerivedToBaseExpr *E, SGFContext C);
RValue visitMetatypeConversionExpr(MetatypeConversionExpr *E,
SGFContext C);
@@ -1103,6 +1104,24 @@ RValue RValueEmitter::visitLoadExpr(LoadExpr *E, SGFContext C) {
C.withFollowingSideEffects());
}
RValue RValueEmitter::visitBorrowExpr(BorrowExpr *E, SGFContext C_Ignored) {
// NOTE: You should NOT add an evaluation scope here!
//
// The callers of this visitor should have established a scope already that
// encompasses the use of the borrowed RValue that we return.
ASSERT(SGF.isInFormalEvaluationScope() && "emit borrow_expr without scope?");
auto accessKind =
SGF.getTypeLowering(E->getType()).isAddress()
? SGFAccessKind::BorrowedAddressRead
: SGFAccessKind::BorrowedObjectRead;
LValue lv = SGF.emitLValue(E->getSubExpr(), accessKind);
auto substFormalType = lv.getSubstFormalType();
ManagedValue mv = SGF.emitBorrowedLValue(E, std::move(lv));
return RValue(SGF, E, substFormalType, mv);
}
SILValue SILGenFunction::emitTemporaryAllocation(SILLocation loc, SILType ty,
HasDynamicLifetime_t dynamic,
IsLexical_t isLexical,

View File

@@ -1131,6 +1131,16 @@ bool TypeChecker::checkedCastMaySucceed(Type t1, Type t2, DeclContext *dc) {
return (kind != CheckedCastKind::Unresolved);
}
Expr *
TypeChecker::addImplicitBorrowExpr(ASTContext &Ctx, Expr *E,
std::function<Type(Expr *)> getType,
std::function<void(Expr *, Type)> setType) {
auto objectType = getType(E)->getRValueType();
auto *BE = BorrowExpr::createImplicit(Ctx, E->getLoc(), E, objectType);
setType(BE, objectType);
return BE;
}
Expr *
TypeChecker::addImplicitLoadExpr(ASTContext &Context, Expr *expr,
std::function<Type(Expr *)> getType,

View File

@@ -882,6 +882,12 @@ Expr *addImplicitLoadExpr(
std::function<void(Expr *, Type)> setType =
[](Expr *E, Type type) { E->setType(type); });
Expr *addImplicitBorrowExpr(
ASTContext &Context, Expr *expr,
std::function<Type(Expr *)> getType = [](Expr *E) { return E->getType(); },
std::function<void(Expr *, Type)> setType =
[](Expr *E, Type type) { E->setType(type); });
/// Determine whether the given type either conforms to, or itself an
/// existential subtype of, the given protocol.
///

View File

@@ -83,7 +83,7 @@ func asyncFunc(_ arg: String) async throws -> Int {
return 1
}
func testUnaryExprs() async throws {
let str = String()
var str = String()
let foo = try await asyncFunc(_borrow str)
let bar = copy foo
let baz = consume foo

View File

@@ -5,11 +5,6 @@ func testGlobal() {
let _ = _borrow global
}
func testLet() {
let t = String()
let _ = _borrow t
}
func testVar() {
var t = String()
t = String()