diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 4a755e6295d..cdda2e79ccc 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1990,8 +1990,6 @@ ERROR(try_assign_rhs_noncovering,none, NOTE(subscript_decl_here,none, "subscript operator declared here", ()) -ERROR(condition_broken_proto,none, - "protocol 'Boolean' is broken", ()) ERROR(broken_bool,none, "type 'Bool' is broken", ()) @@ -2010,9 +2008,6 @@ ERROR(conditional_downcast_foreign,none, ERROR(optional_used_as_boolean,none, "optional type %0 cannot be used as a boolean; " "test for '!= nil' instead", (Type)) -ERROR(optional_used_as_true_boolean,none, - "optional type %0 cannot be used as a boolean; " - "test for '== nil' instead", (Type)) ERROR(interpolation_missing_proto,none, "string interpolation requires the protocol 'ExpressibleByStringInterpolation' to be defined", diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 287f702ecb3..bcf170281ac 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -80,7 +80,6 @@ IDENTIFIER_WITH_NAME(EqualsOperator, "==") // Builtins and literals IDENTIFIER_(MaxBuiltinIntegerType) IDENTIFIER(IntegerLiteralType) -IDENTIFIER(boolValue) IDENTIFIER(nilLiteral) IDENTIFIER(integerLiteral) IDENTIFIER_(builtinIntegerLiteral) diff --git a/include/swift/AST/KnownProtocols.def b/include/swift/AST/KnownProtocols.def index 30bbbfef3c4..1d6a2c90553 100644 --- a/include/swift/AST/KnownProtocols.def +++ b/include/swift/AST/KnownProtocols.def @@ -50,7 +50,6 @@ PROTOCOL(Sequence) PROTOCOL(IteratorProtocol) -PROTOCOL(Boolean) PROTOCOL(AnyObject) PROTOCOL(RawRepresentable) PROTOCOL(Equatable) diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 5a1378105e2..ac4aba10fac 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -5505,7 +5505,6 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) { // The other known protocols aren't special at runtime. case KnownProtocolKind::Sequence: case KnownProtocolKind::IteratorProtocol: - case KnownProtocolKind::Boolean: case KnownProtocolKind::RawRepresentable: case KnownProtocolKind::Equatable: case KnownProtocolKind::Hashable: diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 4f1eea730b7..81e3b0db1a4 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -257,12 +257,6 @@ static DeclTy *findNamedWitnessImpl(TypeChecker &tc, DeclContext *dc, Type type, conformance->getWitness(requirement, &tc).getDecl()); } -static VarDecl *findNamedPropertyWitness(TypeChecker &tc, DeclContext *dc, - Type type, ProtocolDecl *proto, - Identifier name, Diag<> diag) { - return findNamedWitnessImpl(tc, dc, type, proto, name, diag); -} - static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member, DeclContext *DC) { // This only matters for stored properties. @@ -6277,20 +6271,10 @@ bool ConstraintSystem::applySolutionFix(Expr *expr, // If we didn't manage to resolve directly to an expression, we don't // have a great diagnostic to give, so bail. - if (!resolved || !resolved->getAnchor()) + if (!resolved || !resolved->getAnchor() || + !resolved->getPath().empty()) return false; - if (!resolved->getPath().empty()) { - // We allow OptionalToBoolean fixes with an opened type to refer to the - // Boolean conformance. - if (fix.first.getKind() == FixKind::OptionalToBoolean && - resolved->getPath().size() == 1 && - resolved->getPath()[0].getKind() == ConstraintLocator::OpenedGeneric) - ; /* ok */ - else - return false; - } - Expr *affected = resolved->getAnchor(); switch (fix.first.getKind()) { @@ -6381,74 +6365,6 @@ bool ConstraintSystem::applySolutionFix(Expr *expr, return true; } - case FixKind::OptionalToBoolean: { - // If we're implicitly trying to treat an optional type as a boolean, - // let the user know that they should be testing for a value manually - // instead. - Expr *errorExpr = expr; - StringRef prefix = "(("; - StringRef suffix = ") != nil)"; - - // In the common case of a !x, post the error against the inner - // expression as an == comparison. - if (auto PUE = - dyn_cast(errorExpr->getSemanticsProvidingExpr())){ - bool isNot = false; - if (auto *D = PUE->getCalledValue()) - isNot = D->getNameStr() == "!"; - else if (auto *ODR = dyn_cast(PUE->getFn())) - isNot = ODR->getDecls()[0]->getNameStr() == "!"; - - if (isNot) { - suffix = ") == nil)"; - errorExpr = PUE->getArg(); - - // Check if we need the inner parentheses. - // Technically we only need them if there's something in 'expr' with - // lower precedence than '!=', but the code actually comes out nicer - // in most cases with parens on anything non-trivial. - if (errorExpr->canAppendCallParentheses()) { - prefix = prefix.drop_back(); - suffix = suffix.drop_front(); - } - // FIXME: The outer parentheses may be superfluous too. - - - TC.diagnose(errorExpr->getLoc(),diag::optional_used_as_true_boolean, - simplifyType(errorExpr->getType())->getRValueType()) - .fixItRemove(PUE->getLoc()) - .fixItInsert(errorExpr->getStartLoc(), prefix) - .fixItInsertAfter(errorExpr->getEndLoc(), suffix); - return true; - } - } - - // If we can, post the fix-it to the sub-expression if it's a better - // fit. - if (auto ifExpr = dyn_cast(errorExpr)) - errorExpr = ifExpr->getCondExpr(); - if (auto prefixUnaryExpr = dyn_cast(errorExpr)) - errorExpr = prefixUnaryExpr->getArg(); - - - // Check if we need the inner parentheses. - // Technically we only need them if there's something in 'expr' with - // lower precedence than '!=', but the code actually comes out nicer - // in most cases with parens on anything non-trivial. - if (errorExpr->canAppendCallParentheses()) { - prefix = prefix.drop_back(); - suffix = suffix.drop_front(); - } - // FIXME: The outer parentheses may be superfluous too. - - TC.diagnose(errorExpr->getLoc(), diag::optional_used_as_boolean, - simplifyType(errorExpr->getType())->getRValueType()) - .fixItInsert(errorExpr->getStartLoc(), prefix) - .fixItInsertAfter(errorExpr->getEndLoc(), suffix); - - return true; - } - case FixKind::CoerceToCheckedCast: { if (auto *coerceExpr = dyn_cast(locator->getAnchor())) { Expr *subExpr = coerceExpr->getSubExpr(); @@ -6745,25 +6661,16 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc, /// conforms to the give \c protocol. /// \param expr The expression to convert. /// \param locator The locator describing where the conversion occurs. -/// \param protocol The protocol to use for conversion. -/// \param generalName The name of the protocol method to use for the -/// conversion. /// \param builtinName The name of the builtin method to use for the /// last step of the conversion. -/// \param brokenProtocolDiag Diagnostic to emit if the protocol -/// definition is missing. /// \param brokenBuiltinDiag Diagnostic to emit if the builtin definition /// is broken. /// /// \returns the converted expression. -static Expr *convertViaBuiltinProtocol(const Solution &solution, - Expr *expr, - ConstraintLocator *locator, - ProtocolDecl *protocol, - Identifier generalName, - Identifier builtinName, - Diag<> brokenProtocolDiag, - Diag<> brokenBuiltinDiag) { +static Expr *convertViaMember(const Solution &solution, Expr *expr, + ConstraintLocator *locator, + Identifier builtinName, + Diag<> brokenBuiltinDiag) { auto &cs = solution.getConstraintSystem(); // FIXME: Cache name. @@ -6776,66 +6683,17 @@ static Expr *convertViaBuiltinProtocol(const Solution &solution, NameLookupOptions lookupOptions = defaultMemberLookupOptions; if (isa(cs.DC)) lookupOptions |= NameLookupFlags::KnownPrivate; - auto witnesses = tc.lookupMember(cs.DC, type->getRValueType(), builtinName, + auto members = tc.lookupMember(cs.DC, type->getRValueType(), builtinName, lookupOptions); - if (!witnesses) { - auto protocolType = protocol->getType()-> - getAs()->getInstanceType(); - - // Find the witness we need to use. - ValueDecl *witness = nullptr; - - if (!protocolType->isEqual(type)) { - witness = findNamedPropertyWitness(tc, cs.DC, type -> getRValueType(), - protocol, generalName, - brokenProtocolDiag); - } else { - // If the expression is already typed to the protocol, lookup the protocol - // method directly. - witnesses = tc.lookupMember(cs.DC, type->getRValueType(), generalName, - lookupOptions); - if (!witnesses) { - tc.diagnose(protocol->getLoc(), brokenProtocolDiag); - return nullptr; - } - witness = witnesses[0]; - } - - // Form a reference to this member. - Expr *memberRef = new (ctx) MemberRefExpr(expr, expr->getStartLoc(), - witness, - DeclNameLoc(expr->getEndLoc()), - /*Implicit=*/true); - bool failed = tc.typeCheckExpressionShallow(memberRef, cs.DC); - if (failed) { - // If the member reference expression failed to type check, the Expr's - // type does not conform to the given protocol. - tc.diagnose(expr->getLoc(), - diag::type_does_not_conform, - type, - protocol->getType()); - return nullptr; - } - expr = memberRef; - - // At this point, we must have a type with the builtin member. - type = expr->getType(); - witnesses = tc.lookupMember(cs.DC, type->getRValueType(), builtinName, - lookupOptions); - if (!witnesses) { - tc.diagnose(protocol->getLoc(), brokenProtocolDiag); - return nullptr; - } - } - + // Find the builtin method. - if (witnesses.size() != 1) { - tc.diagnose(protocol->getLoc(), brokenBuiltinDiag); + if (members.size() != 1) { + tc.diagnose(expr->getLoc(), brokenBuiltinDiag); return nullptr; } - FuncDecl *builtinMethod = dyn_cast(witnesses[0].Decl); + FuncDecl *builtinMethod = dyn_cast(members[0].Decl); if (!builtinMethod) { - tc.diagnose(protocol->getLoc(), brokenBuiltinDiag); + tc.diagnose(expr->getLoc(), brokenBuiltinDiag); return nullptr; } @@ -6864,15 +6722,9 @@ Expr * Solution::convertBooleanTypeToBuiltinI1(Expr *expr, ConstraintLocator *locator) const { auto &tc = getConstraintSystem().getTypeChecker(); - // FIXME: Cache names. - auto result = convertViaBuiltinProtocol( - *this, expr, locator, - tc.getProtocol(expr->getLoc(), - KnownProtocolKind::Boolean), - tc.Context.Id_boolValue, - tc.Context.Id_getBuiltinLogicValue, - diag::condition_broken_proto, - diag::broken_bool); + auto result = convertViaMember(*this, expr, locator, + tc.Context.Id_getBuiltinLogicValue, + diag::broken_bool); if (result && !result->getType()->isBuiltinIntegerType(1)) { tc.diagnose(expr->getLoc(), diag::broken_bool); return nullptr; diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index f2c4e616bdf..d50df3dd753 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -1874,6 +1874,9 @@ private: /// exact expression kind). bool diagnoseGeneralConversionFailure(Constraint *constraint); + /// Produce a specialized diagnostic if this is an invalid conversion to Bool. + bool diagnoseConversionToBool(Expr *expr, Type exprType); + /// Produce a diagnostic for binary comparisons of the nil literal /// to other values. bool diagnoseNilLiteralComparison(Expr *lhsExpr, Expr *rhsExpr, @@ -2434,6 +2437,46 @@ bool FailureDiagnosis::diagnoseGeneralOverloadFailure(Constraint *constraint) { return true; } +/// Produce a specialized diagnostic if this is an invalid conversion to Bool. +bool FailureDiagnosis::diagnoseConversionToBool(Expr *expr, Type exprType) { + + // Check for "=" converting to Bool. The user probably meant ==. + if (auto *AE = dyn_cast(expr->getValueProvidingExpr())) { + diagnose(AE->getEqualLoc(), diag::use_of_equal_instead_of_equality) + .fixItReplace(AE->getEqualLoc(), "==") + .highlight(AE->getDest()->getLoc()) + .highlight(AE->getSrc()->getLoc()); + return true; + } + + // If we're trying to convert something from optional type to Bool, then a + // comparision against nil was probably expected. + // TODO: It would be nice to handle "!x" --> x == false, but we have no way + // to get to the parent expr at present. + if (exprType->getAnyOptionalObjectType()) { + StringRef prefix = "(("; + StringRef suffix = ") != nil)"; + + // Check if we need the inner parentheses. + // Technically we only need them if there's something in 'expr' with + // lower precedence than '!=', but the code actually comes out nicer + // in most cases with parens on anything non-trivial. + if (expr->canAppendCallParentheses()) { + prefix = prefix.drop_back(); + suffix = suffix.drop_front(); + } + // FIXME: The outer parentheses may be superfluous too. + + diagnose(expr->getLoc(), diag::optional_used_as_boolean, exprType) + .fixItInsert(expr->getStartLoc(), prefix) + .fixItInsertAfter(expr->getEndLoc(), suffix); + return true; + } + + return false; +} + + bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ auto anchor = expr; bool resolvedAnchorToExpr = false; @@ -2563,17 +2606,12 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ return false; + // Check for various issues converting to Bool. + if (toType->isBool() && diagnoseConversionToBool(anchor, fromType)) + return true; + + if (auto PT = toType->getAs()) { - // Check for "=" converting to Boolean. The user probably meant ==. - if (auto *AE = dyn_cast(expr->getValueProvidingExpr())) - if (PT->getDecl()->isSpecificProtocol(KnownProtocolKind::Boolean)) { - diagnose(AE->getEqualLoc(), diag::use_of_equal_instead_of_equality) - .fixItReplace(AE->getEqualLoc(), "==") - .highlight(AE->getDest()->getLoc()) - .highlight(AE->getSrc()->getLoc()); - return true; - } - if (isa(expr->getValueProvidingExpr())) { diagnose(expr->getLoc(), diag::cannot_use_nil_with_this_type, toType) .highlight(expr->getSourceRange()); @@ -3492,30 +3530,10 @@ bool FailureDiagnosis::diagnoseContextualConversionError() { return true; } - // If we're trying to convert something from optional type to Bool, then a - // comparision against nil was probably expected. - // TODO: It would be nice to handle "!x" --> x == false, but we have no way to - // get to the parent expr at present. - if (contextualType->isBool()) - if (exprType->getAnyOptionalObjectType()) { - StringRef prefix = "(("; - StringRef suffix = ") != nil)"; - - // Check if we need the inner parentheses. - // Technically we only need them if there's something in 'expr' with - // lower precedence than '!=', but the code actually comes out nicer - // in most cases with parens on anything non-trivial. - if (expr->canAppendCallParentheses()) { - prefix = prefix.drop_back(); - suffix = suffix.drop_front(); - } - // FIXME: The outer parentheses may be superfluous too. - - diagnose(expr->getLoc(), diag::optional_used_as_boolean, exprType) - .fixItInsert(expr->getStartLoc(), prefix) - .fixItInsertAfter(expr->getEndLoc(), suffix); - return true; - } + // If we're trying to convert something to Bool, check to see if it is for + // a known reason. + if (contextualType->isBool() && diagnoseConversionToBool(expr, exprType)) + return true; exprType = exprType->getRValueType(); @@ -5013,25 +5031,6 @@ bool FailureDiagnosis::visitIfExpr(IfExpr *IE) { auto falseExpr = typeCheckChildIndependently(IE->getElseExpr()); if (!falseExpr) return true; - // Check for "=" converting to Boolean. The user probably meant ==. - if (auto *AE = dyn_cast(condExpr->getValueProvidingExpr())) { - diagnose(AE->getEqualLoc(), diag::use_of_equal_instead_of_equality) - .fixItReplace(AE->getEqualLoc(), "==") - .highlight(AE->getDest()->getLoc()) - .highlight(AE->getSrc()->getLoc()); - return true; - } - - // If the condition wasn't of boolean type, diagnose the problem. - auto booleanType = CS->TC.getProtocol(IE->getQuestionLoc(), - KnownProtocolKind::Boolean); - if (!booleanType) return true; - - if (!CS->TC.conformsToProtocol(condExpr->getType(), booleanType, CS->DC, - ConformanceCheckFlags::InExpression, - nullptr, condExpr->getLoc())) - return true; - // If the true/false values already match, it must be a contextual problem. if (trueExpr->getType()->isEqual(falseExpr->getType())) return false; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index e0ea5ac4a40..c526429f5f2 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2575,16 +2575,15 @@ namespace { Type visitIfExpr(IfExpr *expr) { // The conditional expression must conform to LogicValue. - Expr *condExpr = expr->getCondExpr(); - auto booleanType - = CS.getTypeChecker().getProtocol(expr->getQuestionLoc(), - KnownProtocolKind::Boolean); - if (!booleanType) + auto boolDecl = CS.getASTContext().getBoolDecl(); + if (!boolDecl) return Type(); - CS.addConstraint(ConstraintKind::ConformsTo, condExpr->getType(), - booleanType->getDeclaredType(), - CS.getConstraintLocator(condExpr)); + // Condition must convert to Bool. + CS.addConstraint(ConstraintKind::Conversion, + expr->getCondExpr()->getType(), + boolDecl->getDeclaredType(), + CS.getConstraintLocator(expr->getCondExpr())); // The branches must be convertible to a common type. auto resultTy = CS.createTypeVariable(CS.getConstraintLocator(expr), diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index fcc9dfca2a2..811c0512ef6 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2307,12 +2307,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( // See if there's anything we can do to fix the conformance: OptionalTypeKind optionalKind; if (auto optionalObjectType = type->getAnyOptionalObjectType(optionalKind)) { - if (protocol->isSpecificProtocol(KnownProtocolKind::Boolean)) { - // Optionals don't conform to Boolean; suggest '!= nil'. - if (recordFix(FixKind::OptionalToBoolean, getConstraintLocator(locator))) - return SolutionKind::Error; - return SolutionKind::Solved; - } else if (optionalKind == OTK_Optional) { + if (optionalKind == OTK_Optional) { // The underlying type of an optional may conform to the protocol if the // optional doesn't; suggest forcing if that's the case. auto result = simplifyConformsToConstraint( @@ -4231,10 +4226,6 @@ ConstraintSystem::simplifyFixConstraint(Fix fix, Type type1, Type type2, return matchTypes(InOutType::get(type1->getRValueType()), type2, matchKind, subFlags, locator); - case FixKind::OptionalToBoolean: - // The actual semantics are handled elsewhere. - return SolutionKind::Solved; - case FixKind::CoerceToCheckedCast: llvm_unreachable("handled elsewhere"); } diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index 8ebe995bd8c..6e5935e9fed 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -431,8 +431,6 @@ StringRef Fix::getName(FixKind kind) { return "fix: force downcast"; case FixKind::AddressOf: return "fix: add address-of"; - case FixKind::OptionalToBoolean: - return "fix: convert optional to boolean"; case FixKind::CoerceToCheckedCast: return "fix: as to as!"; } diff --git a/lib/Sema/Constraint.h b/lib/Sema/Constraint.h index 391562cd096..739e7f10973 100644 --- a/lib/Sema/Constraint.h +++ b/lib/Sema/Constraint.h @@ -242,9 +242,6 @@ enum class FixKind : uint8_t { /// Introduce a '&' to take the address of an lvalue. AddressOf, - /// Introduce a '!= nil' to convert an Optional to a Boolean expression. - OptionalToBoolean, - /// Replace a coercion ('as') with a forced checked cast ('as!'). CoerceToCheckedCast, }; diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index f62489eb954..3e1c3bc2266 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2035,20 +2035,15 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) { // Save the original expression. OrigExpr = expr; - // Otherwise, the result must be a Boolean. - auto &tc = cs.getTypeChecker(); - auto logicValueProto = tc.getProtocol(expr->getLoc(), - KnownProtocolKind::Boolean); - if (!logicValueProto) + // Otherwise, the result must be convertible to Bool. + auto boolDecl = cs.getASTContext().getBoolDecl(); + if (!boolDecl) return true; - - auto logicValueType = logicValueProto->getDeclaredType(); - - // We use SelfObjectOfProtocol because an existential Boolean is - // allowed as a condition, but Boolean is not self-conforming. - cs.addConstraint(ConstraintKind::SelfObjectOfProtocol, - expr->getType(), logicValueType, - cs.getConstraintLocator(OrigExpr), /*isFavored*/true); + + // Condition must convert to Bool. + cs.addConstraint(ConstraintKind::Conversion, expr->getType(), + boolDecl->getDeclaredType(), + cs.getConstraintLocator(expr)); return false; } diff --git a/stdlib/public/core/Boolean.swift b/stdlib/public/core/Boolean.swift deleted file mode 100644 index e91e384e8f0..00000000000 --- a/stdlib/public/core/Boolean.swift +++ /dev/null @@ -1,16 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2016 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 -// -//===----------------------------------------------------------------------===// -// Boolean -//===----------------------------------------------------------------------===// - - -// FIXME: Remove this. diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 2cb08dcaa79..c4d71349d17 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -28,7 +28,6 @@ set(SWIFTLIB_ESSENTIAL AssertCommon.swift BidirectionalCollection.swift Bool.swift - Boolean.swift BridgeObjectiveC.swift BridgeStorage.swift Builtin.swift diff --git a/test/Constraints/condition.swift b/test/Constraints/condition.swift deleted file mode 100644 index f9472d9c67f..00000000000 --- a/test/Constraints/condition.swift +++ /dev/null @@ -1,29 +0,0 @@ -// RUN: %target-parse-verify-swift - -// Basic support for Bool -func simpleIf(_ b: Bool) { - if b { } -} - -// Support for non-Bool logic values -struct OtherLogicValue : Boolean { - var boolValue: Bool { return true } -} - -func otherIf(_ b : OtherLogicValue) { - if b { } -} - -// Support for arbitrary logic values in generics -func doIf(_ t: T) { - if t { } -} -doIf(true) - -// Using Boolean-ness to resolve overloading. -func getValue() -> OtherLogicValue {} -func getValue() -> Int {} - -func testLogicValueOverloading() { - if getValue() { } -} diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index b759ad04ef0..264af64edf6 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -192,10 +192,10 @@ func r17224804(_ monthNumber : Int) { // QoI: Operand of postfix '!' should have optional type; type is 'Int?' func r17020197(_ x : Int?, y : Int) { - if x! { } // expected-error {{type 'Int' does not conform to protocol 'Boolean'}} + if x! { } // expected-error {{'Int' is not convertible to 'Bool'}} // QoI: diagnostic for using an integer in a condition is utterly terrible - if y {} // expected-error {{type 'Int' does not conform to protocol 'Boolean'}} + if y {} // expected-error {{'Int' is not convertible to 'Bool'}} } // QoI: Boolean expr not treated as Bool type when function return type is different diff --git a/test/Constraints/if_expr.swift b/test/Constraints/if_expr.swift index f75cf7411de..207b24f7f3b 100644 --- a/test/Constraints/if_expr.swift +++ b/test/Constraints/if_expr.swift @@ -1,11 +1,5 @@ // RUN: %target-parse-verify-swift -struct MyLogicValue : Boolean { - var boolValue: Bool { - return true - } -} - func useInt(_ x: Int) {} func useDouble(_ x: Double) {} @@ -34,7 +28,7 @@ useDouble(c) useDouble(d) var z = true ? a : b // expected-error{{result values in '? :' expression have mismatching types 'Int' and 'Double'}} -var _ = a ? b : b // expected-error{{type 'Int' does not conform to protocol 'Boolean'}} +var _ = a ? b : b // expected-error{{'Int' is not convertible to 'Bool'}} @@ -56,9 +50,9 @@ useB(i) useD1(i) // expected-error{{cannot convert value of type 'B' to expected argument type 'D1'}} useD2(i) // expected-error{{cannot convert value of type 'B' to expected argument type 'D2'}} -var x = MyLogicValue() ? 1 : 0 -var y = 22 ? 1 : 0 // expected-error{{type 'Int' does not conform to protocol 'Boolean'}} +var x = true ? 1 : 0 +var y = 22 ? 1 : 0 // expected-error{{'Int' is not convertible to 'Bool'}} -_ = x ? x : x // expected-error {{type 'Int' does not conform to protocol 'Boolean'}} +_ = x ? x : x // expected-error {{'Int' is not convertible to 'Bool'}} _ = true ? x : 1.2 // expected-error {{result values in '? :' expression have mismatching types 'Int' and 'Double'}} diff --git a/test/Constraints/invalid_logicvalue_coercion.swift b/test/Constraints/invalid_logicvalue_coercion.swift index dd25aa61d01..0886b42528e 100644 --- a/test/Constraints/invalid_logicvalue_coercion.swift +++ b/test/Constraints/invalid_logicvalue_coercion.swift @@ -2,8 +2,8 @@ class C {} var c = C() -if c as C { // expected-error{{type 'C' does not conform to protocol 'Boolean'}} +if c as C { // expected-error{{'C' is not convertible to 'Bool'}} } -if ({1} as () -> Int) { // expected-error{{type '() -> Int' does not conform to protocol 'Boolean'}} +if ({1} as () -> Int) { // expected-error{{'() -> Int' is not convertible to 'Bool'}} } diff --git a/test/Interpreter/builtin_protocol_conversion.swift b/test/Interpreter/builtin_protocol_conversion.swift deleted file mode 100644 index b9fee49c835..00000000000 --- a/test/Interpreter/builtin_protocol_conversion.swift +++ /dev/null @@ -1,7 +0,0 @@ -// RUN: %target-run-simple-swift | FileCheck %s -// REQUIRES: executable_test - -if true as Boolean { - print("true") -} -// CHECK: true diff --git a/test/Misc/misc_diagnostics.swift b/test/Misc/misc_diagnostics.swift index ef50b985f7b..4ae2cc39e8d 100644 --- a/test/Misc/misc_diagnostics.swift +++ b/test/Misc/misc_diagnostics.swift @@ -21,8 +21,8 @@ let total = 15.0 let count = 7 let median = total / count // expected-error {{binary operator '/' cannot be applied to operands of type 'Double' and 'Int'}} expected-note {{overloads for '/' exist with these partially matching parameter lists: (Int, Int), (Double, Double)}} -if (1) {} // expected-error{{type 'Int' does not conform to protocol 'Boolean'}} -if 1 {} // expected-error {{type 'Int' does not conform to protocol 'Boolean'}} +if (1) {} // expected-error{{'Int' is not convertible to 'Bool'}} +if 1 {} // expected-error {{'Int' is not convertible to 'Bool'}} var a: [String] = [1] // expected-error{{cannot convert value of type 'Int' to expected element type 'String'}} var b: Int = [1, 2, 3] // expected-error{{contextual type 'Int' cannot be used with array literal}} diff --git a/test/Parse/foreach.swift b/test/Parse/foreach.swift index 29a77bde965..3618a2abfe0 100644 --- a/test/Parse/foreach.swift +++ b/test/Parse/foreach.swift @@ -30,7 +30,7 @@ func for_each(r: Range, iir: IntRange) { // expected-note 2 {{did you } // Parse errors - for i r { // expected-error 2{{expected ';' in 'for' statement}} expected-error {{use of unresolved identifier 'i'}} expected-error {{type 'Range' does not conform to protocol 'Boolean'}} + for i r { // expected-error 2{{expected ';' in 'for' statement}} expected-error {{use of unresolved identifier 'i'}} expected-error {{'Range' is not convertible to 'Bool'}} } for i in CountableRange(r) sum = sum + i; // expected-error{{expected '{' to start the body of for-each loop}} } diff --git a/test/Parse/switch.swift b/test/Parse/switch.swift index 38e9c5e6341..1bea23407ce 100644 --- a/test/Parse/switch.swift +++ b/test/Parse/switch.swift @@ -64,7 +64,7 @@ case _ where x % 2 == 0, x = 1 case var y where y % 2 == 0: x = y + 1 -case _ where 0: // expected-error {{type 'Int' does not conform to protocol 'Boolean'}} +case _ where 0: // expected-error {{'Int' is not convertible to 'Bool'}} x = 0 default: x = 1 diff --git a/test/TypeCoercion/protocols.swift b/test/TypeCoercion/protocols.swift index 129060ad9f9..bfc01ba8f46 100644 --- a/test/TypeCoercion/protocols.swift +++ b/test/TypeCoercion/protocols.swift @@ -173,5 +173,5 @@ func testREPLPrintable() { doREPLPrint("foo") } -// Boolean coercion -if true as Boolean {} +// Bool coercion +if true as Bool {} diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index 88f078fef14..431bc1af070 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -753,7 +753,7 @@ func testParenExprInTheWay() { //expected-note @-1 {{overloads for '&' exist with these result types: UInt8, Int8, UInt16, Int16, UInt32, Int32, UInt64, Int64, UInt, Int, T, Self}} - if x & x {} // expected-error {{type 'Int' does not conform to protocol 'Boolean'}} + if x & x {} // expected-error {{'Int' is not convertible to 'Bool'}} } // Mixed method/property overload groups can cause a crash during constraint optimization diff --git a/test/stmt/if_while_var.swift b/test/stmt/if_while_var.swift index d4ba5237f30..8181746ecdf 100644 --- a/test/stmt/if_while_var.swift +++ b/test/stmt/if_while_var.swift @@ -72,7 +72,7 @@ if 1 != 2, let x : Int? = opt {} // Test error recovery. // Improve error recovery for malformed if statements -if 1 != 2, { // expected-error {{type '() -> ()' does not conform to protocol 'Boolean'}} +if 1 != 2, { // expected-error {{'() -> ()' is not convertible to 'Bool'}} } // expected-error {{expected '{' after 'if' condition}} if 1 != 2, 4 == 57 {} if 1 != 2, 4 == 57, let x = opt {} diff --git a/test/stmt/statements.swift b/test/stmt/statements.swift index 9f454e23234..6629f4bf487 100644 --- a/test/stmt/statements.swift +++ b/test/stmt/statements.swift @@ -53,8 +53,8 @@ func funcdecl5(_ a: Int, y: Int) { } else if (y == 2) { } - // FIXME: This diagnostic is terrible - rdar://12939553 - if x {} // expected-error {{type 'Int' does not conform to protocol 'Boolean'}} + // This diagnostic is terrible - rdar://12939553 + if x {} // expected-error {{'Int' is not convertible to 'Bool'}} if true { if (B) { @@ -94,7 +94,7 @@ struct infloopbool { } func infloopbooltest() { - if (infloopbool()) {} // expected-error {{type 'infloopbool' does not conform to protocol 'Boolean'}} + if (infloopbool()) {} // expected-error {{'infloopbool' is not convertible to 'Bool'}} } // test "builder" API style diff --git a/validation-test/compiler_crashers_2_fixed/0040-rdar23899799-broken-bool.swift b/validation-test/compiler_crashers_2_fixed/0040-rdar23899799-broken-bool.swift index 36a2668eece..b01c8be1e47 100644 --- a/validation-test/compiler_crashers_2_fixed/0040-rdar23899799-broken-bool.swift +++ b/validation-test/compiler_crashers_2_fixed/0040-rdar23899799-broken-bool.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend %s -emit-silgen +// RUN: %target-swift-frontend %s -emit-silgen // rdar://23899799 let sol1 = { $1 ? "Dr. " + $0 : $0 }