Skip to content

Commit dc24c2b

Browse files
committed
Fix the build.
This reverts commit b4cba58. This reverts commit a602927. This reverts commit 55fbe5a.
1 parent b4cba58 commit dc24c2b

26 files changed

+339
-103
lines changed

Diff for: include/swift/AST/DiagnosticsSema.def

+5
Original file line numberDiff line numberDiff line change
@@ -1990,6 +1990,8 @@ ERROR(try_assign_rhs_noncovering,none,
19901990

19911991
NOTE(subscript_decl_here,none,
19921992
"subscript operator declared here", ())
1993+
ERROR(condition_broken_proto,none,
1994+
"protocol 'Boolean' is broken", ())
19931995

19941996
ERROR(broken_bool,none, "type 'Bool' is broken", ())
19951997

@@ -2008,6 +2010,9 @@ ERROR(conditional_downcast_foreign,none,
20082010
ERROR(optional_used_as_boolean,none,
20092011
"optional type %0 cannot be used as a boolean; "
20102012
"test for '!= nil' instead", (Type))
2013+
ERROR(optional_used_as_true_boolean,none,
2014+
"optional type %0 cannot be used as a boolean; "
2015+
"test for '== nil' instead", (Type))
20112016

20122017
ERROR(interpolation_missing_proto,none,
20132018
"string interpolation requires the protocol 'ExpressibleByStringInterpolation' to be defined",

Diff for: include/swift/AST/KnownIdentifiers.def

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ IDENTIFIER_WITH_NAME(EqualsOperator, "==")
8080
// Builtins and literals
8181
IDENTIFIER_(MaxBuiltinIntegerType)
8282
IDENTIFIER(IntegerLiteralType)
83+
IDENTIFIER(boolValue)
8384
IDENTIFIER(nilLiteral)
8485
IDENTIFIER(integerLiteral)
8586
IDENTIFIER_(builtinIntegerLiteral)

Diff for: include/swift/AST/KnownProtocols.def

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050

5151
PROTOCOL(Sequence)
5252
PROTOCOL(IteratorProtocol)
53+
PROTOCOL(Boolean)
5354
PROTOCOL(AnyObject)
5455
PROTOCOL(RawRepresentable)
5556
PROTOCOL(Equatable)

Diff for: lib/IRGen/GenMeta.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -5505,6 +5505,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
55055505
// The other known protocols aren't special at runtime.
55065506
case KnownProtocolKind::Sequence:
55075507
case KnownProtocolKind::IteratorProtocol:
5508+
case KnownProtocolKind::Boolean:
55085509
case KnownProtocolKind::RawRepresentable:
55095510
case KnownProtocolKind::Equatable:
55105511
case KnownProtocolKind::Hashable:

Diff for: lib/Sema/CSApply.cpp

+163-15
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ static DeclTy *findNamedWitnessImpl(TypeChecker &tc, DeclContext *dc, Type type,
257257
conformance->getWitness(requirement, &tc).getDecl());
258258
}
259259

260+
static VarDecl *findNamedPropertyWitness(TypeChecker &tc, DeclContext *dc,
261+
Type type, ProtocolDecl *proto,
262+
Identifier name, Diag<> diag) {
263+
return findNamedWitnessImpl<VarDecl>(tc, dc, type, proto, name, diag);
264+
}
265+
260266
static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member,
261267
DeclContext *DC) {
262268
// This only matters for stored properties.
@@ -6271,10 +6277,20 @@ bool ConstraintSystem::applySolutionFix(Expr *expr,
62716277

62726278
// If we didn't manage to resolve directly to an expression, we don't
62736279
// have a great diagnostic to give, so bail.
6274-
if (!resolved || !resolved->getAnchor() ||
6275-
!resolved->getPath().empty())
6280+
if (!resolved || !resolved->getAnchor())
62766281
return false;
62776282

6283+
if (!resolved->getPath().empty()) {
6284+
// We allow OptionalToBoolean fixes with an opened type to refer to the
6285+
// Boolean conformance.
6286+
if (fix.first.getKind() == FixKind::OptionalToBoolean &&
6287+
resolved->getPath().size() == 1 &&
6288+
resolved->getPath()[0].getKind() == ConstraintLocator::OpenedGeneric)
6289+
; /* ok */
6290+
else
6291+
return false;
6292+
}
6293+
62786294
Expr *affected = resolved->getAnchor();
62796295

62806296
switch (fix.first.getKind()) {
@@ -6365,6 +6381,74 @@ bool ConstraintSystem::applySolutionFix(Expr *expr,
63656381
return true;
63666382
}
63676383

6384+
case FixKind::OptionalToBoolean: {
6385+
// If we're implicitly trying to treat an optional type as a boolean,
6386+
// let the user know that they should be testing for a value manually
6387+
// instead.
6388+
Expr *errorExpr = expr;
6389+
StringRef prefix = "((";
6390+
StringRef suffix = ") != nil)";
6391+
6392+
// In the common case of a !x, post the error against the inner
6393+
// expression as an == comparison.
6394+
if (auto PUE =
6395+
dyn_cast<PrefixUnaryExpr>(errorExpr->getSemanticsProvidingExpr())){
6396+
bool isNot = false;
6397+
if (auto *D = PUE->getCalledValue())
6398+
isNot = D->getNameStr() == "!";
6399+
else if (auto *ODR = dyn_cast<OverloadedDeclRefExpr>(PUE->getFn()))
6400+
isNot = ODR->getDecls()[0]->getNameStr() == "!";
6401+
6402+
if (isNot) {
6403+
suffix = ") == nil)";
6404+
errorExpr = PUE->getArg();
6405+
6406+
// Check if we need the inner parentheses.
6407+
// Technically we only need them if there's something in 'expr' with
6408+
// lower precedence than '!=', but the code actually comes out nicer
6409+
// in most cases with parens on anything non-trivial.
6410+
if (errorExpr->canAppendCallParentheses()) {
6411+
prefix = prefix.drop_back();
6412+
suffix = suffix.drop_front();
6413+
}
6414+
// FIXME: The outer parentheses may be superfluous too.
6415+
6416+
6417+
TC.diagnose(errorExpr->getLoc(),diag::optional_used_as_true_boolean,
6418+
simplifyType(errorExpr->getType())->getRValueType())
6419+
.fixItRemove(PUE->getLoc())
6420+
.fixItInsert(errorExpr->getStartLoc(), prefix)
6421+
.fixItInsertAfter(errorExpr->getEndLoc(), suffix);
6422+
return true;
6423+
}
6424+
}
6425+
6426+
// If we can, post the fix-it to the sub-expression if it's a better
6427+
// fit.
6428+
if (auto ifExpr = dyn_cast<IfExpr>(errorExpr))
6429+
errorExpr = ifExpr->getCondExpr();
6430+
if (auto prefixUnaryExpr = dyn_cast<PrefixUnaryExpr>(errorExpr))
6431+
errorExpr = prefixUnaryExpr->getArg();
6432+
6433+
6434+
// Check if we need the inner parentheses.
6435+
// Technically we only need them if there's something in 'expr' with
6436+
// lower precedence than '!=', but the code actually comes out nicer
6437+
// in most cases with parens on anything non-trivial.
6438+
if (errorExpr->canAppendCallParentheses()) {
6439+
prefix = prefix.drop_back();
6440+
suffix = suffix.drop_front();
6441+
}
6442+
// FIXME: The outer parentheses may be superfluous too.
6443+
6444+
TC.diagnose(errorExpr->getLoc(), diag::optional_used_as_boolean,
6445+
simplifyType(errorExpr->getType())->getRValueType())
6446+
.fixItInsert(errorExpr->getStartLoc(), prefix)
6447+
.fixItInsertAfter(errorExpr->getEndLoc(), suffix);
6448+
6449+
return true;
6450+
}
6451+
63686452
case FixKind::CoerceToCheckedCast: {
63696453
if (auto *coerceExpr = dyn_cast<CoerceExpr>(locator->getAnchor())) {
63706454
Expr *subExpr = coerceExpr->getSubExpr();
@@ -6661,16 +6745,25 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
66616745
/// conforms to the give \c protocol.
66626746
/// \param expr The expression to convert.
66636747
/// \param locator The locator describing where the conversion occurs.
6748+
/// \param protocol The protocol to use for conversion.
6749+
/// \param generalName The name of the protocol method to use for the
6750+
/// conversion.
66646751
/// \param builtinName The name of the builtin method to use for the
66656752
/// last step of the conversion.
6753+
/// \param brokenProtocolDiag Diagnostic to emit if the protocol
6754+
/// definition is missing.
66666755
/// \param brokenBuiltinDiag Diagnostic to emit if the builtin definition
66676756
/// is broken.
66686757
///
66696758
/// \returns the converted expression.
6670-
static Expr *convertViaMember(const Solution &solution, Expr *expr,
6671-
ConstraintLocator *locator,
6672-
Identifier builtinName,
6673-
Diag<> brokenBuiltinDiag) {
6759+
static Expr *convertViaBuiltinProtocol(const Solution &solution,
6760+
Expr *expr,
6761+
ConstraintLocator *locator,
6762+
ProtocolDecl *protocol,
6763+
Identifier generalName,
6764+
Identifier builtinName,
6765+
Diag<> brokenProtocolDiag,
6766+
Diag<> brokenBuiltinDiag) {
66746767
auto &cs = solution.getConstraintSystem();
66756768

66766769
// FIXME: Cache name.
@@ -6683,17 +6776,66 @@ static Expr *convertViaMember(const Solution &solution, Expr *expr,
66836776
NameLookupOptions lookupOptions = defaultMemberLookupOptions;
66846777
if (isa<AbstractFunctionDecl>(cs.DC))
66856778
lookupOptions |= NameLookupFlags::KnownPrivate;
6686-
auto members = tc.lookupMember(cs.DC, type->getRValueType(), builtinName,
6779+
auto witnesses = tc.lookupMember(cs.DC, type->getRValueType(), builtinName,
66876780
lookupOptions);
6688-
6781+
if (!witnesses) {
6782+
auto protocolType = protocol->getType()->
6783+
getAs<MetatypeType>()->getInstanceType();
6784+
6785+
// Find the witness we need to use.
6786+
ValueDecl *witness = nullptr;
6787+
6788+
if (!protocolType->isEqual(type)) {
6789+
witness = findNamedPropertyWitness(tc, cs.DC, type -> getRValueType(),
6790+
protocol, generalName,
6791+
brokenProtocolDiag);
6792+
} else {
6793+
// If the expression is already typed to the protocol, lookup the protocol
6794+
// method directly.
6795+
witnesses = tc.lookupMember(cs.DC, type->getRValueType(), generalName,
6796+
lookupOptions);
6797+
if (!witnesses) {
6798+
tc.diagnose(protocol->getLoc(), brokenProtocolDiag);
6799+
return nullptr;
6800+
}
6801+
witness = witnesses[0];
6802+
}
6803+
6804+
// Form a reference to this member.
6805+
Expr *memberRef = new (ctx) MemberRefExpr(expr, expr->getStartLoc(),
6806+
witness,
6807+
DeclNameLoc(expr->getEndLoc()),
6808+
/*Implicit=*/true);
6809+
bool failed = tc.typeCheckExpressionShallow(memberRef, cs.DC);
6810+
if (failed) {
6811+
// If the member reference expression failed to type check, the Expr's
6812+
// type does not conform to the given protocol.
6813+
tc.diagnose(expr->getLoc(),
6814+
diag::type_does_not_conform,
6815+
type,
6816+
protocol->getType());
6817+
return nullptr;
6818+
}
6819+
expr = memberRef;
6820+
6821+
// At this point, we must have a type with the builtin member.
6822+
type = expr->getType();
6823+
witnesses = tc.lookupMember(cs.DC, type->getRValueType(), builtinName,
6824+
lookupOptions);
6825+
if (!witnesses) {
6826+
tc.diagnose(protocol->getLoc(), brokenProtocolDiag);
6827+
return nullptr;
6828+
}
6829+
}
6830+
66896831
// Find the builtin method.
6690-
if (members.size() != 1) {
6691-
tc.diagnose(expr->getLoc(), brokenBuiltinDiag);
6832+
if (witnesses.size() != 1) {
6833+
tc.diagnose(protocol->getLoc(), brokenBuiltinDiag);
66926834
return nullptr;
66936835
}
6694-
FuncDecl *builtinMethod = dyn_cast<FuncDecl>(members[0].Decl);
6836+
FuncDecl *builtinMethod = dyn_cast<FuncDecl>(witnesses[0].Decl);
66956837
if (!builtinMethod) {
6696-
tc.diagnose(expr->getLoc(), brokenBuiltinDiag);
6838+
tc.diagnose(protocol->getLoc(), brokenBuiltinDiag);
66976839
return nullptr;
66986840

66996841
}
@@ -6722,9 +6864,15 @@ Expr *
67226864
Solution::convertBooleanTypeToBuiltinI1(Expr *expr, ConstraintLocator *locator) const {
67236865
auto &tc = getConstraintSystem().getTypeChecker();
67246866

6725-
auto result = convertViaMember(*this, expr, locator,
6726-
tc.Context.Id_getBuiltinLogicValue,
6727-
diag::broken_bool);
6867+
// FIXME: Cache names.
6868+
auto result = convertViaBuiltinProtocol(
6869+
*this, expr, locator,
6870+
tc.getProtocol(expr->getLoc(),
6871+
KnownProtocolKind::Boolean),
6872+
tc.Context.Id_boolValue,
6873+
tc.Context.Id_getBuiltinLogicValue,
6874+
diag::condition_broken_proto,
6875+
diag::broken_bool);
67286876
if (result && !result->getType()->isBuiltinIntegerType(1)) {
67296877
tc.diagnose(expr->getLoc(), diag::broken_bool);
67306878
return nullptr;

0 commit comments

Comments
 (0)