diff --git a/lib/AST/TypeJoinMeet.cpp b/lib/AST/TypeJoinMeet.cpp index ae0bc61c0251c..a1af594424502 100644 --- a/lib/AST/TypeJoinMeet.cpp +++ b/lib/AST/TypeJoinMeet.cpp @@ -314,7 +314,7 @@ CanType TypeJoin::visitFunctionType(CanType second) { auto secondExtInfo = secondFnTy->getExtInfo(); // FIXME: Properly handle these attributes. - if (firstExtInfo.withNoEscape(false) != secondExtInfo.withNoEscape(false)) + if (firstExtInfo != secondExtInfo) return Unimplemented; if (!AnyFunctionType::equalParams(firstFnTy->getParams(), diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index e890299c4cf6d..a129fc838c681 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -81,7 +81,7 @@ ConstraintSystem::determineBestBindings() { continue; bindings.addPotentialBinding( - {type, AllowedBindingKind::Supertypes, binding.BindingSource}); + binding.withSameSource(type, AllowedBindingKind::Supertypes)); } } @@ -143,8 +143,8 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding( !binding.BindingType->hasUnresolvedType() && !binding.BindingType->hasTypeVariable() && !binding.BindingType->hasUnboundGenericType() && - !binding.DefaultedProtocol && !binding.isDefaultableBinding() && - allowJoinMeet) { + !binding.hasDefaultedLiteralProtocol() && + !binding.isDefaultableBinding() && allowJoinMeet) { if (lastSupertypeIndex) { auto &lastBinding = Bindings[*lastSupertypeIndex]; auto lastType = lastBinding.BindingType->getWithoutSpecifierType(); @@ -164,7 +164,7 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding( lastSupertypeIndex = Bindings.size(); } - if (auto *literalProtocol = binding.DefaultedProtocol) + if (auto *literalProtocol = binding.getDefaultedLiteralProtocol()) foundLiteralBinding(literalProtocol); // If the type variable can't bind to an lvalue, make sure the @@ -371,7 +371,7 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( kind = AllowedBindingKind::Exact; } - return PotentialBinding{type, kind, constraint->getKind()}; + return PotentialBinding{type, kind, constraint}; } /// Retrieve the set of potential type bindings for the given @@ -466,9 +466,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { path.back().getKind() == ConstraintLocator::ClosureResult && binding->Kind == AllowedBindingKind::Supertypes && exactTypes.insert(voidType).second) { - result.addPotentialBinding( - {voidType, binding->Kind, constraint->getKind()}, - /*allowJoinMeet=*/false); + result.addPotentialBinding({voidType, binding->Kind, constraint}, + /*allowJoinMeet=*/false); } } } @@ -551,9 +550,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { if (!exactTypes.insert(defaultType->getCanonicalType()).second) continue; - literalBindings.push_back({defaultType, AllowedBindingKind::Subtypes, - constraint->getKind(), - constraint->getProtocol()}); + literalBindings.push_back( + {defaultType, AllowedBindingKind::Subtypes, constraint}); continue; } @@ -578,9 +576,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { if (!matched) { exactTypes.insert(defaultType->getCanonicalType()); - literalBindings.push_back({defaultType, AllowedBindingKind::Subtypes, - constraint->getKind(), - constraint->getProtocol()}); + literalBindings.push_back( + {defaultType, AllowedBindingKind::Subtypes, constraint}); } break; @@ -677,7 +674,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { // might be covered by non-defaulted bindings. bool updatedBindingType = false; for (auto &literalBinding : literalBindings) { - auto *protocol = literalBinding.DefaultedProtocol; + auto *protocol = literalBinding.getDefaultedLiteralProtocol(); assert(protocol); @@ -716,7 +713,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { } for (auto &literalBinding : literalBindings) { - auto *protocol = literalBinding.DefaultedProtocol; + auto *protocol = literalBinding.getDefaultedLiteralProtocol(); // For any literal type that has been covered, skip them. if (coveredLiteralProtocols.count(protocol) == 0) result.addPotentialBinding(std::move(literalBinding)); @@ -729,9 +726,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { if (!exactTypes.insert(type->getCanonicalType()).second) continue; - result.addPotentialBinding({type, AllowedBindingKind::Exact, - constraint->getKind(), nullptr, - constraint->getLocator()}); + result.addPotentialBinding({type, AllowedBindingKind::Exact, constraint}); } // If there are no bindings, typeVar may be a hole. @@ -745,9 +740,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { if (locator->isLastElement<LocatorPathElt::MemberRefBase>()) result.PotentiallyIncomplete = true; - result.addPotentialBinding({getASTContext().TheUnresolvedType, - AllowedBindingKind::Exact, ConstraintKind::Defaultable, nullptr, - typeVar->getImpl().getLocator()}); + result.addPotentialBinding( + PotentialBinding::forHole(getASTContext(), locator)); } // Determine if the bindings only constrain the type variable from above with @@ -918,11 +912,11 @@ bool TypeVarBindingProducer::computeNext() { // If we have a protocol with a default type, look for alternative // types to the default. - if (NumTries == 0 && binding.DefaultedProtocol) { - auto knownKind = *(binding.DefaultedProtocol->getKnownProtocolKind()); + if (NumTries == 0 && binding.hasDefaultedLiteralProtocol()) { + auto knownKind = + *(binding.getDefaultedLiteralProtocol()->getKnownProtocolKind()); for (auto altType : CS.getAlternativeLiteralTypes(knownKind)) { - addNewBinding({altType, BindingKind::Subtypes, binding.BindingSource, - binding.DefaultedProtocol}); + addNewBinding(binding.withSameSource(altType, BindingKind::Subtypes)); } } @@ -939,10 +933,10 @@ bool TypeVarBindingProducer::computeNext() { if (auto otherTypeVar = objTy->getAs<TypeVariableType>()) { if (TypeVar->getImpl().canBindToLValue() == otherTypeVar->getImpl().canBindToLValue()) { - addNewBinding({objTy, binding.Kind, binding.BindingSource}); + addNewBinding(binding.withSameSource(objTy, binding.Kind)); } } else { - addNewBinding({objTy, binding.Kind, binding.BindingSource}); + addNewBinding(binding.withSameSource(objTy, binding.Kind)); } } } @@ -953,7 +947,7 @@ bool TypeVarBindingProducer::computeNext() { for (auto supertype : enumerateDirectSupertypes(type)) { // If we're not allowed to try this binding, skip it. if (auto simplifiedSuper = CS.checkTypeOfBinding(TypeVar, supertype)) - addNewBinding({*simplifiedSuper, binding.Kind, binding.BindingSource}); + addNewBinding(binding.withType(*simplifiedSuper)); } } @@ -968,12 +962,13 @@ bool TypeVarBindingProducer::computeNext() { bool TypeVariableBinding::attempt(ConstraintSystem &cs) const { auto type = Binding.BindingType; - auto *locator = TypeVar->getImpl().getLocator(); + auto *srcLocator = Binding.getLocator(); + auto *dstLocator = TypeVar->getImpl().getLocator(); - if (Binding.DefaultedProtocol) { - type = cs.openUnboundGenericType(type, locator); + if (Binding.hasDefaultedLiteralProtocol()) { + type = cs.openUnboundGenericType(type, dstLocator); type = type->reconstituteSugar(/*recursive=*/false); - } else if (Binding.BindingSource == ConstraintKind::ArgumentConversion && + } else if (srcLocator->isLastElement<LocatorPathElt::ApplyArgToParam>() && !type->hasTypeVariable() && cs.isCollectionType(type)) { // If the type binding comes from the argument conversion, let's // instead of binding collection types directly, try to bind @@ -984,27 +979,27 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const { auto UGT = UnboundGenericType::get(BGT->getDecl(), BGT->getParent(), BGT->getASTContext()); - type = cs.openUnboundGenericType(UGT, locator); + type = cs.openUnboundGenericType(UGT, dstLocator); type = type->reconstituteSugar(/*recursive=*/false); } - // FIXME: We want the locator that indicates where the binding came - // from. - cs.addConstraint(ConstraintKind::Bind, TypeVar, type, locator); + cs.addConstraint(ConstraintKind::Bind, TypeVar, type, srcLocator); // If this was from a defaultable binding note that. if (Binding.isDefaultableBinding()) { - cs.DefaultedConstraints.push_back(Binding.DefaultableBinding); - - if (locator->isForGenericParameter() && type->isHole()) { - // Drop `generic parameter` locator element so that all missing - // generic parameters related to the same path can be coalesced later. - auto path = locator->getPath(); - auto genericParam = locator->getGenericParameter(); - auto *fix = DefaultGenericArgument::create(cs, genericParam, - cs.getConstraintLocator(locator->getAnchor(), path.drop_back())); - if (cs.recordFix(fix)) - return true; + cs.DefaultedConstraints.push_back(srcLocator); + + if (type->isHole()) { + if (auto *GP = TypeVar->getImpl().getGenericParameter()) { + auto path = dstLocator->getPath(); + // Drop `generic parameter` locator element so that all missing + // generic parameters related to the same path can be coalesced later. + auto *fix = DefaultGenericArgument::create( + cs, GP, + cs.getConstraintLocator(dstLocator->getAnchor(), path.drop_back())); + if (cs.recordFix(fix)) + return true; + } } } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index cb9804d868c83..56a2bbc21829a 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -897,27 +897,23 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseAsError() { if (diagnoseParameterUse()) return true; - if (ConvertTo) { - emitDiagnostic(anchor->getLoc(), diag::converting_noescape_to_type, - ConvertTo); - return true; + if (auto *typeVar = getRawFromType()->getAs<TypeVariableType>()) { + if (auto *GP = typeVar->getImpl().getGenericParameter()) { + emitDiagnostic(anchor->getLoc(), diag::converting_noescape_to_type, GP); + return true; + } } - auto *loc = getLocator(); - if (auto gpElt = loc->getLastElementAs<LocatorPathElt::GenericParameter>()) { - auto *paramTy = gpElt->getType(); - emitDiagnostic(anchor->getLoc(), diag::converting_noescape_to_type, - paramTy); - } else { - emitDiagnostic(anchor->getLoc(), diag::unknown_escaping_use_of_noescape); - } + emitDiagnostic(anchor->getLoc(), diag::converting_noescape_to_type, + getToType()); return true; } bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const { + auto convertTo = getToType(); // If the other side is not a function, we have common case diagnostics // which handle function-to-type conversion diagnostics. - if (!ConvertTo || !ConvertTo->is<FunctionType>()) + if (!convertTo->is<FunctionType>()) return false; auto *anchor = getAnchor(); @@ -943,7 +939,9 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const { diag::converting_noespace_param_to_generic_type, PD->getName(), paramInterfaceTy); - emitDiagnostic(decl, diag::generic_parameters_always_escaping); + auto declLoc = decl->getLoc(); + if (declLoc.isValid()) + emitDiagnostic(decl, diag::generic_parameters_always_escaping); }; // If this is a situation when non-escaping parameter is passed @@ -2032,6 +2030,9 @@ bool ContextualFailure::diagnoseAsError() { return true; } + auto fromType = getFromType(); + auto toType = getToType(); + Diag<Type, Type> diagnostic; switch (path.back().getKind()) { case ConstraintLocator::ClosureResult: { @@ -2040,9 +2041,8 @@ bool ContextualFailure::diagnoseAsError() { closure->getExplicitResultTypeLoc().getTypeRepr()) { auto resultRepr = closure->getExplicitResultTypeLoc().getTypeRepr(); emitDiagnostic(resultRepr->getStartLoc(), - diag::incorrect_explicit_closure_result, getFromType(), - getToType()) - .fixItReplace(resultRepr->getSourceRange(), getToType().getString()); + diag::incorrect_explicit_closure_result, fromType, toType) + .fixItReplace(resultRepr->getSourceRange(), toType.getString()); return true; } @@ -2071,22 +2071,21 @@ bool ContextualFailure::diagnoseAsError() { return true; if (CTP == CTP_ForEachStmt) { - if (FromType->isAnyExistentialType()) { + if (fromType->isAnyExistentialType()) { emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform, - /*isExistentialType=*/true, FromType, ToType); + /*isExistentialType=*/true, fromType, toType); return true; } emitDiagnostic( anchor->getLoc(), diag::foreach_sequence_does_not_conform_to_expected_protocol, - FromType, ToType, bool(FromType->getOptionalObjectType())) + fromType, toType, bool(fromType->getOptionalObjectType())) .highlight(anchor->getSourceRange()); return true; } - auto contextualType = getToType(); - if (auto msg = getDiagnosticFor(CTP, contextualType->isExistentialType())) { + if (auto msg = getDiagnosticFor(CTP, toType->isExistentialType())) { diagnostic = *msg; break; } @@ -2102,11 +2101,11 @@ bool ContextualFailure::diagnoseAsError() { return false; auto *choice = overload->choice.getDecl(); - auto fnType = FromType->getAs<FunctionType>(); + auto fnType = fromType->getAs<FunctionType>(); if (!fnType) { emitDiagnostic(anchor->getLoc(), diag::expected_result_in_contextual_member, - choice->getFullName(), FromType, ToType); + choice->getFullName(), fromType, toType); return true; } @@ -2151,7 +2150,8 @@ bool ContextualFailure::diagnoseAsError() { return false; } - auto diag = emitDiagnostic(anchor->getLoc(), diagnostic, FromType, ToType); + auto diag = + emitDiagnostic(anchor->getLoc(), diagnostic, fromType, toType); diag.highlight(anchor->getSourceRange()); (void)tryFixIts(diag); @@ -2357,12 +2357,13 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const { if (getLocator()->isLastElement<LocatorPathElt::RValueAdjustment>()) return false; - auto *srcFT = FromType->getAs<FunctionType>(); + auto *srcFT = getFromType()->getAs<FunctionType>(); if (!srcFT || !srcFT->getParams().empty()) return false; - if (ToType->is<AnyFunctionType>() || - !TypeChecker::isConvertibleTo(srcFT->getResult(), ToType, getDC())) + auto toType = getToType(); + if (toType->is<AnyFunctionType>() || + !TypeChecker::isConvertibleTo(srcFT->getResult(), toType, getDC())) return false; auto *anchor = getAnchor(); @@ -2663,7 +2664,10 @@ bool ContextualFailure::tryRawRepresentableFixIts( bool ContextualFailure::tryIntegerCastFixIts( InFlightDiagnostic &diagnostic) const { - if (!isIntegerType(FromType) || !isIntegerType(ToType)) + auto fromType = getFromType(); + auto toType = getToType(); + + if (!isIntegerType(fromType) || !isIntegerType(toType)) return false; auto getInnerCastedExpr = [&](Expr *expr) -> Expr * { @@ -2684,7 +2688,7 @@ bool ContextualFailure::tryIntegerCastFixIts( auto *anchor = getAnchor(); if (Expr *innerE = getInnerCastedExpr(anchor)) { Type innerTy = getType(innerE); - if (TypeChecker::isConvertibleTo(innerTy, ToType, getDC())) { + if (TypeChecker::isConvertibleTo(innerTy, toType, getDC())) { // Remove the unnecessary cast. diagnostic.fixItRemoveChars(anchor->getLoc(), innerE->getStartLoc()) .fixItRemove(anchor->getEndLoc()); @@ -2693,7 +2697,7 @@ bool ContextualFailure::tryIntegerCastFixIts( } // Add a wrapping integer cast. - std::string convWrapBefore = ToType.getString(); + std::string convWrapBefore = toType.getString(); convWrapBefore += "("; std::string convWrapAfter = ")"; SourceRange exprRange = anchor->getSourceRange(); @@ -2715,8 +2719,8 @@ bool ContextualFailure::trySequenceSubsequenceFixIts( // Substring -> String conversion // Wrap in String.init - if (FromType->isEqual(Substring)) { - if (ToType->isEqual(String)) { + if (getFromType()->isEqual(Substring)) { + if (getToType()->isEqual(String)) { auto *anchor = getAnchor()->getSemanticsProvidingExpr(); auto range = anchor->getSourceRange(); diagnostic.fixItInsert(range.Start, "String("); @@ -2775,10 +2779,11 @@ bool ContextualFailure::tryProtocolConformanceFixIt( if (!nominal) return false; + auto fromType = getFromType(); // We need to get rid of optionals and parens as it's not relevant when // printing the diagnostic and the fix-it. auto unwrappedToType = - ToType->lookThroughAllOptionalTypes()->getWithoutParens(); + getToType()->lookThroughAllOptionalTypes()->getWithoutParens(); // If the protocol requires a class & we don't have one (maybe the context // is a struct), then bail out instead of offering a broken fix-it later on. @@ -2789,13 +2794,13 @@ bool ContextualFailure::tryProtocolConformanceFixIt( requiresClass = layout.requiresClass(); } - if (requiresClass && !FromType->is<ClassType>()) { + if (requiresClass && !fromType->is<ClassType>()) { return false; } // We can only offer a fix-it if we're assigning to a protocol type and // the type we're assigning is the same as the innermost type context. - bool shouldOfferFixIt = nominal->getSelfTypeInContext()->isEqual(FromType) && + bool shouldOfferFixIt = nominal->getSelfTypeInContext()->isEqual(fromType) && unwrappedToType->isExistentialType(); if (!shouldOfferFixIt) return false; @@ -2805,7 +2810,7 @@ bool ContextualFailure::tryProtocolConformanceFixIt( // Let's build a list of protocols that the context does not conform to. SmallVector<std::string, 8> missingProtoTypeStrings; for (auto protocol : layout.getProtocols()) { - if (!TypeChecker::conformsToProtocol(FromType, protocol->getDecl(), getDC(), + if (!TypeChecker::conformsToProtocol(fromType, protocol->getDecl(), getDC(), ConformanceCheckFlags::InExpression)) { missingProtoTypeStrings.push_back(protocol->getString()); } @@ -2833,7 +2838,7 @@ bool ContextualFailure::tryProtocolConformanceFixIt( // TODO: Maybe also insert the requirement stubs? auto conformanceDiag = emitDiagnostic( getAnchor()->getLoc(), diag::assign_protocol_conformance_fix_it, - unwrappedToType, nominal->getDescriptiveKind(), FromType); + unwrappedToType, nominal->getDescriptiveKind(), fromType); if (nominal->getInherited().size() > 0) { auto lastInherited = nominal->getInherited().back().getLoc(); auto lastInheritedEndLoc = diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 67cc1ddcc342b..e314546d0a0ad 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -585,26 +585,6 @@ class LabelingFailure final : public FailureDiagnostic { bool diagnoseAsNote() override; }; -/// Diagnose errors related to converting function type which -/// isn't explicitly '@escaping' to some other type. -class NoEscapeFuncToTypeConversionFailure final : public FailureDiagnostic { - Type ConvertTo; - -public: - NoEscapeFuncToTypeConversionFailure(ConstraintSystem &cs, - ConstraintLocator *locator, - Type toType = Type()) - : FailureDiagnostic(cs, locator), ConvertTo(toType) {} - - bool diagnoseAsError() override; - -private: - /// Emit tailored diagnostics for no-escape parameter conversions e.g. - /// passing such parameter as an @escaping argument, or trying to - /// assign it to a variable which expects @escaping function. - bool diagnoseParameterUse() const; -}; - /// Diagnose failures related to attempting member access on optional base /// type without optional chaining or force-unwrapping it first. class MemberAccessOnOptionalBaseFailure final : public FailureDiagnostic { @@ -694,7 +674,7 @@ class AssignmentFailure final : public FailureDiagnostic { /// e.g. argument/parameter, closure result, conversions etc. class ContextualFailure : public FailureDiagnostic { ContextualTypePurpose CTP; - Type FromType, ToType; + Type RawFromType, RawToType; public: ContextualFailure(ConstraintSystem &cs, Type lhs, Type rhs, @@ -702,15 +682,18 @@ class ContextualFailure : public FailureDiagnostic { : ContextualFailure(cs, cs.getContextualTypePurpose(), lhs, rhs, locator) {} - ContextualFailure(ConstraintSystem &cs, - ContextualTypePurpose purpose, Type lhs, Type rhs, - ConstraintLocator *locator) - : FailureDiagnostic(cs, locator), CTP(purpose), - FromType(resolve(lhs)), ToType(resolve(rhs)) {} + ContextualFailure(ConstraintSystem &cs, ContextualTypePurpose purpose, + Type lhs, Type rhs, ConstraintLocator *locator) + : FailureDiagnostic(cs, locator), CTP(purpose), RawFromType(lhs), + RawToType(rhs) {} + + Type getFromType() const { return resolve(RawFromType); } - Type getFromType() const { return FromType; } + Type getToType() const { return resolve(RawToType); } - Type getToType() const { return ToType; } + Type getRawFromType() const { return RawFromType; } + + Type getRawToType() const { return RawToType; } bool diagnoseAsError() override; @@ -791,7 +774,7 @@ class ContextualFailure : public FailureDiagnostic { Type contextualType); private: - Type resolve(Type rawType) { + Type resolve(Type rawType) const { return resolveType(rawType)->getWithoutSpecifierType(); } @@ -816,6 +799,23 @@ class ContextualFailure : public FailureDiagnostic { getDiagnosticFor(ContextualTypePurpose context, bool forProtocol); }; +/// Diagnose errors related to converting function type which +/// isn't explicitly '@escaping' to some other type. +class NoEscapeFuncToTypeConversionFailure final : public ContextualFailure { +public: + NoEscapeFuncToTypeConversionFailure(ConstraintSystem &cs, Type fromType, + Type toType, ConstraintLocator *locator) + : ContextualFailure(cs, fromType, toType, locator) {} + + bool diagnoseAsError() override; + +private: + /// Emit tailored diagnostics for no-escape parameter conversions e.g. + /// passing such parameter as an @escaping argument, or trying to + /// assign it to a variable which expects @escaping function. + bool diagnoseParameterUse() const; +}; + /// Diagnose failures related to use of the unwrapped optional types, /// which require some type of force-unwrap e.g. "!" or "try!". class MissingOptionalUnwrapFailure final : public ContextualFailure { diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index f06cc25a28b6f..e038e43eabe07 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -159,16 +159,16 @@ CoerceToCheckedCast *CoerceToCheckedCast::attempt(ConstraintSystem &cs, } bool MarkExplicitlyEscaping::diagnose(bool asNote) const { - NoEscapeFuncToTypeConversionFailure failure(getConstraintSystem(), - getLocator(), ConvertTo); + auto &cs = getConstraintSystem(); + NoEscapeFuncToTypeConversionFailure failure(cs, getFromType(), getToType(), + getLocator()); return failure.diagnose(asNote); } MarkExplicitlyEscaping * -MarkExplicitlyEscaping::create(ConstraintSystem &cs, ConstraintLocator *locator, - Type convertingTo) { - return new (cs.getAllocator()) - MarkExplicitlyEscaping(cs, locator, convertingTo); +MarkExplicitlyEscaping::create(ConstraintSystem &cs, Type lhs, Type rhs, + ConstraintLocator *locator) { + return new (cs.getAllocator()) MarkExplicitlyEscaping(cs, lhs, rhs, locator); } bool RelabelArguments::diagnose(bool asNote) const { diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index e31bc01dcff3c..4b739c3a4461a 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -322,27 +322,6 @@ class TreatRValueAsLValue final : public ConstraintFix { ConstraintLocator *locator); }; -/// Mark function type as explicitly '@escaping'. -class MarkExplicitlyEscaping final : public ConstraintFix { - /// Sometimes function type has to be marked as '@escaping' - /// to be converted to some other generic type. - Type ConvertTo; - - MarkExplicitlyEscaping(ConstraintSystem &cs, ConstraintLocator *locator, - Type convertingTo = Type()) - : ConstraintFix(cs, FixKind::ExplicitlyEscaping, locator), - ConvertTo(convertingTo) {} - -public: - std::string getName() const override { return "add @escaping"; } - - bool diagnose(bool asNote = false) const override; - - static MarkExplicitlyEscaping *create(ConstraintSystem &cs, - ConstraintLocator *locator, - Type convertingTo = Type()); -}; - /// Arguments have labeling failures - missing/extraneous or incorrect /// labels attached to the, fix it by suggesting proper labels. class RelabelArguments final @@ -496,6 +475,22 @@ class ContextualMismatch : public ConstraintFix { ConstraintLocator *locator); }; +/// Mark function type as explicitly '@escaping'. +class MarkExplicitlyEscaping final : public ContextualMismatch { + MarkExplicitlyEscaping(ConstraintSystem &cs, Type lhs, Type rhs, + ConstraintLocator *locator) + : ContextualMismatch(cs, FixKind::ExplicitlyEscaping, lhs, rhs, locator) { + } + +public: + std::string getName() const override { return "add @escaping"; } + + bool diagnose(bool asNote = false) const override; + + static MarkExplicitlyEscaping *create(ConstraintSystem &cs, Type lhs, + Type rhs, ConstraintLocator *locator); +}; + /// Introduce a '!' to force an optional unwrap. class ForceOptional final : public ContextualMismatch { ForceOptional(ConstraintSystem &cs, Type fromType, Type toType, diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index ebe4d6c145eec..60cfaf48ed40a 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1548,8 +1548,8 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, if (!shouldAttemptFixes()) return getTypeMatchFailure(locator); - auto *fix = MarkExplicitlyEscaping::create( - *this, getConstraintLocator(locator), func2); + auto *fix = MarkExplicitlyEscaping::create(*this, func1, func2, + getConstraintLocator(locator)); if (recordFix(fix)) return getTypeMatchFailure(locator); @@ -2084,9 +2084,8 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2, return getTypeMatchSuccess(); if (shouldAttemptFixes()) { - auto &ctx = getASTContext(); - auto *fix = MarkExplicitlyEscaping::create( - *this, getConstraintLocator(locator), ctx.TheAnyType); + auto *fix = MarkExplicitlyEscaping::create(*this, type1, type2, + getConstraintLocator(locator)); if (!recordFix(fix)) return getTypeMatchSuccess(); } @@ -2348,8 +2347,8 @@ ConstraintSystem::matchTypesBindTypeVar( // but we still have a non-escaping type, fail. if (!typeVar->getImpl().canBindToNoEscape() && type->isNoEscape()) { if (shouldAttemptFixes()) { - auto *fix = MarkExplicitlyEscaping::create( - *this, getConstraintLocator(locator)); + auto *fix = MarkExplicitlyEscaping::create(*this, typeVar, type, + getConstraintLocator(locator)); if (recordFix(fix)) return getTypeMatchFailure(locator); diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index acf0092439bbf..06542222c4212 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3288,28 +3288,64 @@ class ConstraintSystem { /// The kind of bindings permitted. AllowedBindingKind Kind; - /// The kind of the constraint this binding came from. - ConstraintKind BindingSource; - - /// The defaulted protocol associated with this binding. - ProtocolDecl *DefaultedProtocol; - - /// If this is a binding that comes from a \c Defaultable constraint, - /// the locator of that constraint. - ConstraintLocator *DefaultableBinding = nullptr; + protected: + /// The source of the type information. + /// + /// Determines whether this binding represents a "hole" in + /// constraint system. Such bindings have no originating constraint + /// because they are synthetic, they have a locator instead. + PointerUnion<Constraint *, ConstraintLocator *> BindingSource; PotentialBinding(Type type, AllowedBindingKind kind, - ConstraintKind bindingSource, - ProtocolDecl *defaultedProtocol = nullptr, - ConstraintLocator *defaultableBinding = nullptr) + PointerUnion<Constraint *, ConstraintLocator *> source) + : BindingType(type->getWithoutParens()), Kind(kind), + BindingSource(source) {} + + public: + PotentialBinding(Type type, AllowedBindingKind kind, Constraint *source) : BindingType(type->getWithoutParens()), Kind(kind), - BindingSource(bindingSource), DefaultedProtocol(defaultedProtocol), - DefaultableBinding(defaultableBinding) {} + BindingSource(source) {} + + bool isDefaultableBinding() const { + if (auto *constraint = BindingSource.dyn_cast<Constraint *>()) + return constraint->getKind() == ConstraintKind::Defaultable; + // If binding source is not constraint - it's a hole, which is + // a last resort default binding for a type variable. + return true; + } + + bool hasDefaultedLiteralProtocol() const { + return bool(getDefaultedLiteralProtocol()); + } + + ProtocolDecl *getDefaultedLiteralProtocol() const { + auto *constraint = BindingSource.dyn_cast<Constraint *>(); + if (!constraint) + return nullptr; - bool isDefaultableBinding() const { return DefaultableBinding != nullptr; } + return constraint->getKind() == ConstraintKind::LiteralConformsTo + ? constraint->getProtocol() + : nullptr; + } + + ConstraintLocator *getLocator() const { + if (auto *constraint = BindingSource.dyn_cast<Constraint *>()) + return constraint->getLocator(); + return BindingSource.get<ConstraintLocator *>(); + } PotentialBinding withType(Type type) const { - return {type, Kind, BindingSource, DefaultedProtocol, DefaultableBinding}; + return {type, Kind, BindingSource}; + } + + PotentialBinding withSameSource(Type type, AllowedBindingKind kind) const { + return {type, kind, BindingSource}; + } + + static PotentialBinding forHole(ASTContext &ctx, + ConstraintLocator *locator) { + return {ctx.TheUnresolvedType, AllowedBindingKind::Exact, + /*source=*/locator}; } }; @@ -3464,9 +3500,8 @@ class ConstraintSystem { out << "(supertypes of) "; break; } - if (binding.DefaultedProtocol) - out << "(default from " - << binding.DefaultedProtocol->getName() << ") "; + if (auto *literal = binding.getDefaultedLiteralProtocol()) + out << "(default from " << literal->getName() << ") "; out << type.getString(PO); }, [&]() { out << "; "; }); @@ -4196,7 +4231,9 @@ class TypeVariableBinding { bool isDefaultable() const { return Binding.isDefaultableBinding(); } - bool hasDefaultedProtocol() const { return Binding.DefaultedProtocol; } + bool hasDefaultedProtocol() const { + return Binding.hasDefaultedLiteralProtocol(); + } bool attempt(ConstraintSystem &cs) const; diff --git a/test/Constraints/function.swift b/test/Constraints/function.swift index 596bf9d52a34f..be6b85bde7f12 100644 --- a/test/Constraints/function.swift +++ b/test/Constraints/function.swift @@ -85,7 +85,7 @@ sr590(()) sr590((1, 2)) // SR-2657: Poor diagnostics when function arguments should be '@escaping'. -private class SR2657BlockClass<T> { // expected-note 3 {{generic parameters are always considered '@escaping'}} +private class SR2657BlockClass<T> { // expected-note 4 {{generic parameters are always considered '@escaping'}} let f: T init(f: T) { self.f = f } } @@ -94,7 +94,7 @@ func takesAny(_: Any) {} func foo(block: () -> (), other: () -> Int) { let _ = SR2657BlockClass(f: block) - // expected-error@-1 {{converting non-escaping value to 'T' may allow it to escape}} + // expected-error@-1 {{converting non-escaping parameter 'block' to generic parameter 'T' may allow it to escape}} let _ = SR2657BlockClass<()->()>(f: block) // expected-error@-1 {{converting non-escaping parameter 'block' to generic parameter 'T' may allow it to escape}} let _: SR2657BlockClass<()->()> = SR2657BlockClass(f: block) diff --git a/test/Constraints/suspicious_bit_casts.swift b/test/Constraints/suspicious_bit_casts.swift index 5e5148d791b4d..baaf382d1230f 100644 --- a/test/Constraints/suspicious_bit_casts.swift +++ b/test/Constraints/suspicious_bit_casts.swift @@ -2,7 +2,7 @@ func escapeByBitCast(f: () -> ()) -> () -> () { return unsafeBitCast(f, to: (() -> ()).self) - // expected-error@-1 {{converting non-escaping value to 'T' may allow it to escape}} + // expected-error@-1 {{converting non-escaping parameter 'f' to generic parameter 'T' may allow it to escape}} } func changeFnRep(f: @escaping () -> ()) -> @convention(block) () -> () { diff --git a/test/Sema/type_join.swift b/test/Sema/type_join.swift index 96d9724029f9e..ad6d2b78cdc27 100644 --- a/test/Sema/type_join.swift +++ b/test/Sema/type_join.swift @@ -31,7 +31,7 @@ protocol FakeExpressibleByFloatLiteral {} protocol FakeBinaryFloatingPoint : FakeFloatingPoint, FakeExpressibleByFloatLiteral {} func expectEqualType<T>(_: T.Type, _: T.Type) {} -func commonSupertype<T>(_: T, _: T) -> T {} +func commonSupertype<T>(_: T, _: T) -> T {} // expected-note 2 {{generic parameters are always considered '@escaping'}} expectEqualType(Builtin.type_join(Int.self, Int.self), Int.self) expectEqualType(Builtin.type_join_meta(D.self, C.self), C.self) @@ -90,9 +90,9 @@ func joinFunctions( ) { _ = commonSupertype(escaping, escaping) _ = commonSupertype(nonescaping, escaping) - // expected-error@-1 {{converting non-escaping value to 'T' may allow it to escape}} + // expected-error@-1 {{converting non-escaping parameter 'nonescaping' to generic parameter 'T' may allow it to escape}} _ = commonSupertype(escaping, nonescaping) - // expected-error@-1 {{converting non-escaping value to 'T' may allow it to escape}} + // expected-error@-1 {{converting non-escaping parameter 'nonescaping' to generic parameter 'T' may allow it to escape}} let x: Int = 1 // FIXME: We emit these diagnostics here because we refuse to allow // Any to be inferred for the generic type. That's pretty diff --git a/test/attr/attr_autoclosure.swift b/test/attr/attr_autoclosure.swift index 10bb792144eda..4c136c330414e 100644 --- a/test/attr/attr_autoclosure.swift +++ b/test/attr/attr_autoclosure.swift @@ -183,10 +183,10 @@ func passAutoClosureToEnumCase(_ fn: @autoclosure () -> Int) { func rdar_20591571() { func foo(_ g: @autoclosure () -> Int) { typealias G = ()->Int - let _ = unsafeBitCast(g, to: G.self) // expected-error {{converting non-escaping value to 'T' may allow it to escape}} + let _ = unsafeBitCast(g, to: G.self) // expected-error {{converting non-escaping parameter 'g' to generic parameter 'T' may allow it to escape}} } - func id<T>(_: T) -> T {} + func id<T>(_: T) -> T {} // expected-note {{eneric parameters are always considered '@escaping'}} func same<T>(_: T, _: T) {} // expected-note@-1 2 {{generic parameters are always considered '@escaping'}} @@ -198,7 +198,7 @@ func rdar_20591571() { var _ = efn let _ = efn - _ = id(fn) // expected-error {{converting non-escaping value to 'T' may allow it to escape}} + _ = id(fn) // expected-error {{converting non-escaping parameter 'fn' to generic parameter 'T' may allow it to escape}} _ = same(fn, { 3 }) // expected-error {{converting non-escaping parameter 'fn' to generic parameter 'T' may allow it to escape}} _ = same({ 3 }, fn) // expected-error {{converting non-escaping parameter 'fn' to generic parameter 'T' may allow it to escape}} @@ -251,7 +251,7 @@ func overloaded_autoclj(_: @autoclosure () -> Int) {} func autoclosure_param_returning_func_type() { func foo(_ fn: @autoclosure () -> (() -> Int)) {} - func generic_foo<T>(_ fn: @autoclosure () -> T) {} + func generic_foo<T>(_ fn: @autoclosure () -> T) {} // expected-note {{generic parameters are always considered '@escaping'}} func bar_1(_ fn: @autoclosure @escaping () -> Int) { foo(fn) } // Ok func bar_2(_ fn: @autoclosure () -> Int) { foo(fn) } // expected-note {{parameter 'fn' is implicitly non-escaping}} @@ -259,7 +259,7 @@ func autoclosure_param_returning_func_type() { func baz_1(_ fn: @autoclosure @escaping () -> Int) { generic_foo(fn) } // Ok (T is inferred as () -> Int) func baz_2(_ fn: @autoclosure @escaping () -> Int) { generic_foo(fn()) } // Ok (T is inferred as Int) func baz_3(_ fn: @autoclosure () -> Int) { generic_foo(fn) } // Fails because fn is not marked as @escaping - // expected-error@-1 {{converting non-escaping value to 'T' may allow it to escape}} + // expected-error@-1 {{converting non-escaping parameter 'fn' to generic parameter 'T' may allow it to escape}} // Let's make sure using `fn` as value works fine in presence of overloading func biz_1(_ fn: @autoclosure @escaping () -> Int) { overloaded_autoclj(fn) } // Ok diff --git a/test/attr/attr_noescape.swift b/test/attr/attr_noescape.swift index d5244fc324dcd..d22bccde0f388 100644 --- a/test/attr/attr_noescape.swift +++ b/test/attr/attr_noescape.swift @@ -11,7 +11,7 @@ func takesGenericClosure<T>(_ a : Int, _ fn : @noescape () -> T) {} // expected- var globalAny: Any = 0 -func assignToGlobal<T>(_ t: T) { +func assignToGlobal<T>(_ t: T) { // expected-note {{generic parameters are always considered '@escaping'}} globalAny = t } @@ -23,7 +23,7 @@ func takesVariadic(_ fns: () -> Int...) { doesEscape(fns[0]) // Okay - variadic-of-function parameters are escaping } -func takesNoEscapeClosure(_ fn : () -> Int) { +func takesNoEscapeClosure(_ fn : () -> Int) { // expected-note 2 {{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }} // expected-note@-1 5{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }} takesNoEscapeClosure { 4 } // ok @@ -36,14 +36,14 @@ func takesNoEscapeClosure(_ fn : () -> Int) { takesGenericClosure(4, fn) // ok takesGenericClosure(4) { fn() } // ok. - _ = [fn] // expected-error {{converting non-escaping value to 'Element' may allow it to escape}} + _ = [fn] // expected-error {{using non-escaping parameter 'fn' in a context expecting an @escaping closure}} _ = [doesEscape(fn)] // expected-error {{passing non-escaping parameter 'fn' to function expecting an @escaping closure}} - _ = [1 : fn] // expected-error {{converting non-escaping value to 'Value' may allow it to escape}} + _ = [1 : fn] // expected-error {{using non-escaping parameter 'fn' in a context expecting an @escaping closure}} _ = [1 : doesEscape(fn)] // expected-error {{passing non-escaping parameter 'fn' to function expecting an @escaping closure}} _ = "\(doesEscape(fn))" // expected-error {{passing non-escaping parameter 'fn' to function expecting an @escaping closure}} _ = "\(takesArray([fn]))" // expected-error {{using non-escaping parameter 'fn' in a context expecting an @escaping closure}} - assignToGlobal(fn) // expected-error {{converting non-escaping value to 'T' may allow it to escape}} + assignToGlobal(fn) // expected-error {{converting non-escaping parameter 'fn' to generic parameter 'T' may allow it to escape}} assignToGlobal((fn, fn)) // expected-error {{converting non-escaping value to 'T' may allow it to escape}} } diff --git a/test/expr/primary/keypath/keypath-objc.swift b/test/expr/primary/keypath/keypath-objc.swift index 27f638daa35b0..e8a5988f02bc8 100644 --- a/test/expr/primary/keypath/keypath-objc.swift +++ b/test/expr/primary/keypath/keypath-objc.swift @@ -160,7 +160,7 @@ class SR_10146_3 { } func doNotCrash_1(_ obj: AnyObject, _ kp: KeyPath<AnyObject, Int>) { - let _ = obj[keyPath: \.abc] // expected-error 2{{the root type of a Swift key path cannot be 'AnyObject'}} + let _ = obj[keyPath: \.abc] // expected-error {{the root type of a Swift key path cannot be 'AnyObject'}} let _ = obj[keyPath: kp] // expected-error {{the root type of a Swift key path cannot be 'AnyObject'}} } }