Skip to content

[SR-8272] Drop the last remnants of LogicValue #21451

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
Dec 21, 2018
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
1 change: 0 additions & 1 deletion include/swift/AST/KnownIdentifiers.def
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ IDENTIFIER(appendInterpolation)
IDENTIFIER_WITH_NAME(dollarInterpolation, "$interpolation")
IDENTIFIER(arrayLiteral)
IDENTIFIER(dictionaryLiteral)
IDENTIFIER_(getBuiltinLogicValue)
IDENTIFIER(className)

IDENTIFIER_(ErrorType)
Expand Down
6 changes: 3 additions & 3 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ class Verifier : public ASTWalker {
case StmtConditionElement::CK_Boolean: {
auto *E = elt.getBoolean();
if (shouldVerifyChecked(E))
checkSameType(E->getType(), BuiltinIntegerType::get(1, Ctx),
checkSameType(E->getType(), Ctx.getBoolDecl()->getDeclaredType(),
"condition type");
break;
}
Expand Down Expand Up @@ -2070,8 +2070,8 @@ class Verifier : public ASTWalker {
PrettyStackTraceExpr debugStack(Ctx, "verifying IfExpr", E);

auto condTy = E->getCondExpr()->getType();
if (!condTy->isBuiltinIntegerType(1)) {
Out << "IfExpr condition is not an i1\n";
if (!condTy->isBool()) {
Out << "IfExpr condition is not Bool\n";
abort();
}

Expand Down
16 changes: 7 additions & 9 deletions lib/SILGen/SILGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,9 +696,12 @@ copyOrInitValueInto(SILGenFunction &SGF, SILLocation loc,
getUnmanagedValue();
}

assert(testBool->getType().getASTType()->isBool());
auto i1Value = SGF.emitUnwrapIntegerResult(loc, testBool);

SILBasicBlock *contBB = SGF.B.splitBlockForFallthrough();
auto falseBB = SGF.Cleanups.emitBlockForCleanups(getFailureDest(), loc);
SGF.B.createCondBranch(loc, testBool, contBB, falseBB);
SGF.B.createCondBranch(loc, i1Value, contBB, falseBB);

SGF.B.setInsertionPoint(contBB);
}
Expand Down Expand Up @@ -995,13 +998,7 @@ copyOrInitValueInto(SILGenFunction &SGF, SILLocation loc,
assert(isInit && "Only initialization is supported for refutable patterns");

// Extract the i1 from the Bool struct.
StructDecl *BoolStruct = cast<StructDecl>(SGF.getASTContext().getBoolDecl());
auto Members = BoolStruct->lookupDirect(SGF.getASTContext().Id_value_);
assert(Members.size() == 1 &&
"Bool should have only one property with name '_value'");
auto Member = dyn_cast<VarDecl>(Members[0]);
assert(Member &&"Bool should have a property with name '_value' of type Int1");
auto *i1Val = SGF.B.createStructExtract(loc, value.forward(SGF), Member);
auto i1Value = SGF.emitUnwrapIntegerResult(loc, value.forward(SGF));

// Branch on the boolean based on whether we're testing for true or false.
SILBasicBlock *trueBB = SGF.B.splitBlockForFallthrough();
Expand All @@ -1010,7 +1007,7 @@ copyOrInitValueInto(SILGenFunction &SGF, SILLocation loc,

if (!pattern->getValue())
std::swap(trueBB, falseBB);
SGF.B.createCondBranch(loc, i1Val, trueBB, falseBB);
SGF.B.createCondBranch(loc, i1Value, trueBB, falseBB);
SGF.B.setInsertionPoint(contBB);
}

Expand Down Expand Up @@ -1264,6 +1261,7 @@ void SILGenFunction::emitStmtCondition(StmtCondition Cond, JumpDest FalseDest,
// Evaluate the condition as an i1 value (guaranteed by Sema).
FullExpr Scope(Cleanups, CleanupLocation(expr));
booleanTestValue = emitRValue(expr).forwardAsSingleValue(*this, expr);
booleanTestValue = emitUnwrapIntegerResult(expr, booleanTestValue);
booleanTestLoc = expr;
break;
}
Expand Down
21 changes: 1 addition & 20 deletions lib/SILGen/SILGenForeignError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,25 +281,6 @@ void SILGenFunction::emitForeignErrorBlock(SILLocation loc,
emitThrow(loc, error);
}

/// Unwrap a value of a wrapped integer type to get at the juicy
/// Builtin.IntegerN value within.
static SILValue emitUnwrapIntegerResult(SILGenFunction &SGF,
SILLocation loc,
SILValue value) {
// This is a loop because we want to handle types that wrap integer types,
// like ObjCBool (which may be Bool or Int8).
while (!value->getType().is<BuiltinIntegerType>()) {
auto structDecl = value->getType().getStructOrBoundGenericStruct();
assert(structDecl && "value for error result wasn't of struct type!");
assert(std::next(structDecl->getStoredProperties().begin())
== structDecl->getStoredProperties().end());
auto property = *structDecl->getStoredProperties().begin();
value = SGF.B.createStructExtract(loc, value, property);
}

return value;
}

/// Perform a foreign error check by testing whether the call result is zero.
/// The call result is otherwise ignored.
static void
Expand All @@ -312,7 +293,7 @@ emitResultIsZeroErrorCheck(SILGenFunction &SGF, SILLocation loc,
}

SILValue resultValue =
emitUnwrapIntegerResult(SGF, loc, result.getUnmanagedValue());
SGF.emitUnwrapIntegerResult(loc, result.getUnmanagedValue());
auto resultType = resultValue->getType().getASTType();

if (!resultType->isBuiltinIntegerType(1)) {
Expand Down
16 changes: 16 additions & 0 deletions lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -687,3 +687,19 @@ Optional<ASTNode> SILGenFunction::getPGOParent(ASTNode Node) const {
return SP->getPGOParent(Node);
return None;
}

SILValue SILGenFunction::emitUnwrapIntegerResult(SILLocation loc,
SILValue value) {
// This is a loop because we want to handle types that wrap integer types,
// like ObjCBool (which may be Bool or Int8).
while (!value->getType().is<BuiltinIntegerType>()) {
auto structDecl = value->getType().getStructOrBoundGenericStruct();
assert(structDecl && "value for error result wasn't of struct type!");
assert(std::next(structDecl->getStoredProperties().begin())
== structDecl->getStoredProperties().end());
auto property = *structDecl->getStoredProperties().begin();
value = B.createStructExtract(loc, value, property);
}

return value;
}
2 changes: 2 additions & 0 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
SILValue semanticValue,
SILType storageType);

SILValue emitUnwrapIntegerResult(SILLocation loc, SILValue value);

/// Load an r-value out of the given address. This does not handle
/// reabstraction or bridging. If that is needed, use the other emit load
/// entry point.
Expand Down
15 changes: 5 additions & 10 deletions lib/SILGen/SILGenPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,9 @@ void PatternMatchEmission::emitGuardBranch(SILLocation loc, Expr *guard,
testBool = SGF.emitRValueAsSingleValue(guard).getUnmanagedValue();
}

SGF.B.createCondBranch(loc, testBool, trueBB, falseBB);
// Extract the i1 from the Bool struct.
auto i1Value = SGF.emitUnwrapIntegerResult(loc, testBool);
SGF.B.createCondBranch(loc, i1Value, trueBB, falseBB);

SGF.B.setInsertionPoint(falseBB);
failure(loc);
Expand Down Expand Up @@ -2250,15 +2252,8 @@ emitBoolDispatch(ArrayRef<RowToSpecialize> rows, ConsumableManagedValue src,
SILValue srcValue = src.getFinalManagedValue().forward(SGF);

// Extract the i1 from the Bool struct.
StructDecl *BoolStruct = cast<StructDecl>(Context.getBoolDecl());
auto Members = BoolStruct->lookupDirect(Context.Id_value_);
assert(Members.size() == 1 &&
"Bool should have only one property with name '_value'");
auto Member = dyn_cast<VarDecl>(Members[0]);
assert(Member &&"Bool should have a property with name '_value' of type Int1");
auto *ETI = SGF.B.createStructExtract(loc, srcValue, Member);

SGF.B.createSwitchValue(loc, SILValue(ETI), defaultBB, caseBBs);
auto i1Value = SGF.emitUnwrapIntegerResult(loc, srcValue);
SGF.B.createSwitchValue(loc, i1Value, defaultBB, caseBBs);

// Okay, now emit all the cases.
for (unsigned i = 0, e = caseInfos.size(); i != e; ++i) {
Expand Down
13 changes: 6 additions & 7 deletions lib/SILGen/SILGenStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,14 @@ Condition SILGenFunction::emitCondition(Expr *E, bool invertValue,
assert(B.hasValidInsertionPoint() &&
"emitting condition at unreachable point");

// Sema forces conditions to have Builtin.i1 type, which guarantees this.
// Sema forces conditions to have Bool type, which guarantees this.
SILValue V;
{
FullExpr Scope(Cleanups, CleanupLocation(E));
V = emitRValue(E).forwardAsSingleValue(*this, E);
}
assert(V->getType().castTo<BuiltinIntegerType>()->isFixedWidth(1));

return emitCondition(V, E, invertValue, contArgs, NumTrueTaken,
auto i1Value = emitUnwrapIntegerResult(E, V);
return emitCondition(i1Value, E, invertValue, contArgs, NumTrueTaken,
NumFalseTaken);
}

Expand Down Expand Up @@ -525,16 +524,16 @@ void StmtEmitter::visitPoundAssertStmt(PoundAssertStmt *stmt) {
SGF.emitRValueAsSingleValue(stmt->getCondition()).getUnmanagedValue();
}

// Sema forces conditions to have Builtin.i1 type.
assert(condition->getType().castTo<BuiltinIntegerType>()->isFixedWidth(1));
// Extract the i1 from the Bool struct.
auto i1Value = SGF.emitUnwrapIntegerResult(stmt, condition);

SILValue message = SGF.B.createStringLiteral(
stmt, stmt->getMessage(), StringLiteralInst::Encoding::UTF8);

auto resultType = SGF.getASTContext().TheEmptyTupleType;
SGF.B.createBuiltin(
stmt, SGF.getASTContext().getIdentifier("poundAssert"),
SGF.getLoweredType(resultType), {}, {condition, message});
SGF.getLoweredType(resultType), {}, {i1Value, message});
}

namespace {
Expand Down
80 changes: 1 addition & 79 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3143,10 +3143,7 @@ namespace {
auto resultTy = simplifyType(cs.getType(expr));
cs.setType(expr, resultTy);

// Convert the condition to a logic value.
auto cond
= solution.convertBooleanTypeToBuiltinI1(expr->getCondExpr(),
cs.getConstraintLocator(expr));
auto cond = cs.coerceToRValue(expr->getCondExpr());
expr->setCondExpr(cond);

// Coerce the then/else branches to the common type.
Expand Down Expand Up @@ -8010,81 +8007,6 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
return result;
}

Expr *
Solution::convertBooleanTypeToBuiltinI1(Expr *expr,
ConstraintLocator *locator) const {
auto &cs = getConstraintSystem();

// Load lvalues here.
expr = cs.coerceToRValue(expr);

auto &tc = cs.getTypeChecker();
auto &ctx = tc.Context;

auto type = cs.getType(expr);

// We allow UnresolvedType <c $T for all $T, so we might end up here
// in diagnostics. Just bail out.
if (type->is<UnresolvedType>())
return expr;

// Look for the builtin name. If we don't have it, we need to call the
// general name via the witness table.
NameLookupOptions lookupOptions = defaultMemberLookupOptions;
if (isa<AbstractFunctionDecl>(cs.DC))
lookupOptions |= NameLookupFlags::KnownPrivate;
auto members = tc.lookupMember(cs.DC, type,
tc.Context.Id_getBuiltinLogicValue,
lookupOptions);

// Find the builtin method.
if (members.size() != 1) {
tc.diagnose(expr->getLoc(), diag::broken_bool);
return expr;
}
auto *builtinMethod = dyn_cast<FuncDecl>(members[0].getValueDecl());
if (!builtinMethod) {
tc.diagnose(expr->getLoc(), diag::broken_bool);
return expr;
}

// The method is not generic, so there are no substitutions.
tc.validateDeclForNameLookup(builtinMethod);
auto builtinMethodType = builtinMethod->getInterfaceType()
->castTo<FunctionType>();

// Form an unbound reference to the builtin method.
auto *declRef = new (ctx) DeclRefExpr(builtinMethod,
DeclNameLoc(expr->getLoc()),
/*Implicit=*/true);
declRef->setFunctionRefKind(FunctionRefKind::DoubleApply);
cs.setType(declRef, builtinMethodType);

auto getType = [&](const Expr *E) -> Type {
return cs.getType(E);
};

// Apply 'self' to get the method value.
auto *methodRef = new (ctx) DotSyntaxCallExpr(declRef,
SourceLoc(),
expr);
cs.setType(methodRef, builtinMethodType->getResult());

// Apply the empty argument list to get the final result.
auto *result = CallExpr::createImplicit(ctx, methodRef,
{ }, { }, getType);
cs.setType(result, builtinMethodType->getResult()
->castTo<FunctionType>()->getResult());
cs.setType(result->getArg(), ctx.TheEmptyTupleType);

if (!cs.getType(result)->isBuiltinIntegerType(1)) {
tc.diagnose(expr->getLoc(), diag::broken_bool);
return result;
}

return result;
}

Expr *Solution::convertOptionalToBool(Expr *expr,
ConstraintLocator *locator) const {
auto &cs = getConstraintSystem();
Expand Down
16 changes: 0 additions & 16 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3313,22 +3313,6 @@ namespace {
continue;
}

// Strip off 'Bool' to 'Builtin.Int1' conversion. Otherwise, we'll have
// to handle multiple ways of type-checking.
if (expr->isImplicit()) {
if (auto call = dyn_cast<CallExpr>(expr)) {
if (auto DSCE = dyn_cast<DotSyntaxCallExpr>(call->getFn())) {
auto RefD = DSCE->getFn()->getReferencedDecl().getDecl();
if (RefD->getBaseName() == TC.Context.Id_getBuiltinLogicValue &&
RefD->getDeclContext()->getSelfNominalTypeDecl() ==
TC.Context.getBoolDecl()) {
expr = DSCE->getBase();
continue;
}
}
}
}

// Remove any semantic expression injected by typechecking.
if (auto CE = dyn_cast<CollectionExpr>(expr)) {
CE->setSemanticExpr(nullptr);
Expand Down
13 changes: 0 additions & 13 deletions lib/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -636,19 +636,6 @@ class Solution {
bool ignoreTopLevelInjection = false,
Optional<Pattern*> typeFromPattern = None) const;

/// Convert the given expression to a logic value.
///
/// This operation cannot fail.
///
/// \param expr The expression to coerce. The type of this expression
/// must conform to the LogicValue protocol.
///
/// \param locator Locator used to describe the location of this expression.
///
/// \returns the expression converted to a logic value (Builtin i1).
Expr *convertBooleanTypeToBuiltinI1(Expr *expr,
ConstraintLocator *locator) const;

/// Convert the given optional-producing expression to a Bool
/// indicating whether the optional has a value.
///
Expand Down
20 changes: 3 additions & 17 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2699,10 +2699,9 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
}

bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
// If this expression is already typechecked and has an i1 type, then it has
// already got its conversion from Boolean back to i1. Just re-typecheck
// it.
if (expr->getType() && expr->getType()->isBuiltinIntegerType(1)) {
// If this expression is already typechecked and has type Bool, then just
// re-typecheck it.
if (expr->getType() && expr->getType()->isBool()) {
auto resultTy = typeCheckExpression(expr, dc);
return !resultTy;
}
Expand All @@ -2728,19 +2727,6 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
cs.getConstraintLocator(expr));
return false;
}

// Convert the result to a Builtin.i1.
Expr *appliedSolution(constraints::Solution &solution,
Expr *expr) override {
auto &cs = solution.getConstraintSystem();

auto converted =
solution.convertBooleanTypeToBuiltinI1(expr,
cs.getConstraintLocator(OrigExpr));
cs.setExprTypes(converted);
return converted;
}

};

ConditionListener listener;
Expand Down
9 changes: 0 additions & 9 deletions stdlib/public/core/Bool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,6 @@ extension Bool : _ExpressibleByBuiltinBooleanLiteral, ExpressibleByBooleanLitera
}
}

extension Bool {
// This is a magic entry point known to the compiler.
@_transparent
public // COMPILER_INTRINSIC
func _getBuiltinLogicValue() -> Builtin.Int1 {
return _value
}
}

extension Bool : CustomStringConvertible {
/// A textual representation of the Boolean value.
@inlinable
Expand Down
Loading