Skip to content
Open
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
18 changes: 18 additions & 0 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2508,6 +2508,24 @@ class Verifier : public ASTWalker {
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);

Expand Down
19 changes: 19 additions & 0 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
2 changes: 1 addition & 1 deletion test/ASTGen/exprs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 0 additions & 5 deletions test/Parse/borrow_expr.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ func testGlobal() {
let _ = _borrow global
}

func testLet() {
let t = String()
let _ = _borrow t
}

func testVar() {
var t = String()
t = String()
Expand Down