diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index 0ab6aa7ed1083..248d8e7496261 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -552,31 +552,30 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { /// /// \param lookupKind The kind of lookup to perform. /// - /// \param diagnostics If non-null, will be populated with the set of - /// diagnostics that should be emitted for this declaration context. /// FIXME: This likely makes more sense on IterableDeclContext or /// something similar. SmallVector getLocalProtocols(ConformanceLookupKind lookupKind - = ConformanceLookupKind::All, - SmallVectorImpl *diagnostics - = nullptr) const; + = ConformanceLookupKind::All) const; /// Retrieve the set of protocol conformances associated with this /// declaration context. /// /// \param lookupKind The kind of lookup to perform. /// - /// \param diagnostics If non-null, will be populated with the set of - /// diagnostics that should be emitted for this declaration context. - /// /// FIXME: This likely makes more sense on IterableDeclContext or /// something similar. SmallVector getLocalConformances(ConformanceLookupKind lookupKind - = ConformanceLookupKind::All, - SmallVectorImpl *diagnostics - = nullptr) const; + = ConformanceLookupKind::All) const; + + /// Retrieve diagnostics discovered while expanding conformances for this + /// declaration context. This operation then removes those diagnostics from + /// consideration, so subsequent calls to this function with the same + /// declaration context that have not had any new extensions bound + /// will see an empty array. + SmallVector + takeConformanceDiagnostics() const; /// Retrieves a list of separately imported overlays which are shadowing /// \p declaring. If any \p overlays are returned, qualified lookups into diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 43aca22824906..d1797db598ccd 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1200,8 +1200,16 @@ ERROR(c_function_pointer_from_method,none, ERROR(c_function_pointer_from_generic_function,none, "a C function pointer cannot be formed from a reference to a generic " "function", ()) +ERROR(unsupported_linear_to_differentiable_conversion,none, + "conversion from '@differentiable(linear)' to '@differentiable' is not " + "yet supported", ()) ERROR(invalid_autoclosure_forwarding,none, "add () to forward @autoclosure parameter", ()) +ERROR(invalid_differentiable_function_conversion_expr,none, + "a '@differentiable%select{|(linear)}0' function can only be formed from " + "a reference to a 'func' or a literal closure", (bool)) +NOTE(invalid_differentiable_function_conversion_parameter,none, + "did you mean to take a '%0' closure?", (StringRef)) ERROR(invalid_autoclosure_pointer_conversion,none, "cannot perform pointer conversion of value of type %0 to autoclosure " "result type %1", @@ -4016,6 +4024,18 @@ ERROR(opaque_type_in_protocol_requirement,none, ERROR(attr_only_on_parameters_of_differentiable,none, "'%0' may only be used on parameters of '@differentiable' function " "types", (StringRef)) +ERROR(differentiable_function_type_invalid_parameter,none, + "parameter type '%0' does not conform to 'Differentiable'" + "%select{| and satisfy '%0 == %0.TangentVector'}1, but the enclosing " + "function type is '@differentiable%select{|(linear)}1'" + "%select{|; did you want to add '@noDerivative' to this parameter?}2", + (StringRef, /*tangentVectorEqualsSelf*/ bool, + /*hasValidDifferentiabilityParameter*/ bool)) +ERROR(differentiable_function_type_invalid_result,none, + "result type '%0' does not conform to 'Differentiable'" + "%select{| and satisfy '%0 == %0.TangentVector'}1, but the enclosing " + "function type is '@differentiable%select{|(linear)}1'", + (StringRef, bool)) // SIL ERROR(opened_non_protocol,none, diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index abd2f65f145ac..a8d34a2212f51 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -2966,6 +2966,61 @@ class UnevaluatedInstanceExpr : public ImplicitConversionExpr { } }; +class DifferentiableFunctionExpr : public ImplicitConversionExpr { +public: + DifferentiableFunctionExpr(Expr *subExpr, Type ty) + : ImplicitConversionExpr(ExprKind::DifferentiableFunction, subExpr, ty) {} + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::DifferentiableFunction; + } +}; + +class LinearFunctionExpr : public ImplicitConversionExpr { +public: + LinearFunctionExpr(Expr *subExpr, Type ty) + : ImplicitConversionExpr(ExprKind::LinearFunction, subExpr, ty) {} + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::LinearFunction; + } +}; + +class DifferentiableFunctionExtractOriginalExpr + : public ImplicitConversionExpr { +public: + DifferentiableFunctionExtractOriginalExpr(Expr *subExpr, Type ty) + : ImplicitConversionExpr(ExprKind::DifferentiableFunctionExtractOriginal, + subExpr, ty) {} + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::DifferentiableFunctionExtractOriginal; + } +}; + +class LinearFunctionExtractOriginalExpr : public ImplicitConversionExpr { +public: + LinearFunctionExtractOriginalExpr(Expr *subExpr, Type ty) + : ImplicitConversionExpr(ExprKind::LinearFunctionExtractOriginal, + subExpr, ty) {} + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::LinearFunctionExtractOriginal; + } +}; + +class LinearToDifferentiableFunctionExpr : public ImplicitConversionExpr { +public: + LinearToDifferentiableFunctionExpr(Expr *subExpr, Type ty) + : ImplicitConversionExpr( + ExprKind::LinearToDifferentiableFunction, subExpr, ty) {} + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::LinearToDifferentiableFunction; + } +}; + + /// Use an opaque type to abstract a value of the underlying concrete type. class UnderlyingToOpaqueExpr : public ImplicitConversionExpr { public: diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index 7ea0fb0435e8c..fb28680bbd9a1 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -170,7 +170,12 @@ ABSTRACT_EXPR(ImplicitConversion, Expr) EXPR(ForeignObjectConversion, ImplicitConversionExpr) EXPR(UnevaluatedInstance, ImplicitConversionExpr) EXPR(UnderlyingToOpaque, ImplicitConversionExpr) - EXPR_RANGE(ImplicitConversion, Load, UnderlyingToOpaque) + EXPR(DifferentiableFunction, ImplicitConversionExpr) + EXPR(LinearFunction, ImplicitConversionExpr) + EXPR(DifferentiableFunctionExtractOriginal, ImplicitConversionExpr) + EXPR(LinearFunctionExtractOriginal, ImplicitConversionExpr) + EXPR(LinearToDifferentiableFunction, ImplicitConversionExpr) + EXPR_RANGE(ImplicitConversion, Load, LinearToDifferentiableFunction) ABSTRACT_EXPR(ExplicitCast, Expr) ABSTRACT_EXPR(CheckedCast, ExplicitCastExpr) EXPR(ForcedCheckedCast, CheckedCastExpr) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index e87342fc67fe0..9938dd1c85f69 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -2185,6 +2185,39 @@ class ClosureHasExplicitResultRequest bool isCached() const { return true; } }; +using ProtocolConformanceLookupResult = SmallVector; +void simple_display(llvm::raw_ostream &out, ConformanceLookupKind kind); + +/// Lookup and expand all conformances in the given context. +/// +/// This request specifically accomodates algorithms for retrieving all +/// conformances in the primary, even those that are unstated in source but +/// are implied by other conformances, inherited from other types, or synthesized +/// by the compiler. A simple case of this is the following: +/// +/// \code +/// protocol P {} +/// protocol Q : P {} +/// extension T : Q {} +/// \endcode +/// +/// Here, a conformance to \c Q has been stated, but a conformance to \c P +/// must also be reported so it can be checked as well. +class LookupAllConformancesInContextRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected + evaluate(Evaluator &evaluator, const DeclContext *DC) const; +}; + // Allow AnyValue to compare two Type values, even though Type doesn't // support ==. template<> diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 39329f067b29e..7dccd03e8ecfd 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -236,3 +236,6 @@ SWIFT_REQUEST(TypeChecker, ScopedImportLookupRequest, ArrayRef(ImportDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, ClosureHasExplicitResultRequest, bool(ClosureExpr *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, LookupAllConformancesInContextRequest, + ProtocolConformanceLookupResult(const DeclContext *), + Uncached, NoLocationInfo) diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index 97ce7be6ce815..61174385d77a9 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -2189,6 +2189,14 @@ class SILBuilder { ExtracteeType)); } + DifferentiableFunctionExtractInst * + createDifferentiableFunctionExtractOriginal(SILLocation Loc, + SILValue TheFunction) { + return insert(new (getModule()) DifferentiableFunctionExtractInst( + getModule(), getSILDebugLocation(Loc), + NormalDifferentiableFunctionTypeComponent::Original, TheFunction)); + } + LinearFunctionExtractInst *createLinearFunctionExtract( SILLocation Loc, LinearDifferentiableFunctionTypeComponent Extractee, SILValue TheFunction) { diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index a84383d465039..4bf6b0439f718 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -253,6 +253,8 @@ PASS(PredictableMemoryAccessOptimizations, "predictable-memaccess-opts", "Predictable Memory Access Optimizations for Diagnostics") PASS(PredictableDeadAllocationElimination, "predictable-deadalloc-elim", "Eliminate dead temporary allocations after diagnostics") +PASS(RedundantPhiElimination, "redundant-phi-elimination", + "Redundant Phi Block Argument Elimination") PASS(ReleaseDevirtualizer, "release-devirtualizer", "SIL release Devirtualization") PASS(RetainSinking, "retain-sinking", diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index a02ac4d0999d3..403b4194c1085 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2354,6 +2354,34 @@ class PrintExpr : public ExprVisitor { printRec(E->getSubExpr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + void visitDifferentiableFunctionExpr(DifferentiableFunctionExpr *E) { + printCommon(E, "differentiable_function") << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitLinearFunctionExpr(LinearFunctionExpr *E) { + printCommon(E, "linear_function") << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitDifferentiableFunctionExtractOriginalExpr( + DifferentiableFunctionExtractOriginalExpr *E) { + printCommon(E, "differentiable_function_extract_original") << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitLinearFunctionExtractOriginalExpr( + LinearFunctionExtractOriginalExpr *E) { + printCommon(E, "linear_function_extract_original") << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitLinearToDifferentiableFunctionExpr( + LinearToDifferentiableFunctionExpr *E) { + printCommon(E, "linear_to_differentiable_function") << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } void visitInOutExpr(InOutExpr *E) { printCommon(E, "inout_expr") << '\n'; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index c1c221cbfad0c..c28001799baa0 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -349,6 +349,11 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const { PASS_THROUGH_REFERENCE(PointerToPointer, getSubExpr); PASS_THROUGH_REFERENCE(ForeignObjectConversion, getSubExpr); PASS_THROUGH_REFERENCE(UnevaluatedInstance, getSubExpr); + PASS_THROUGH_REFERENCE(DifferentiableFunction, getSubExpr); + PASS_THROUGH_REFERENCE(LinearFunction, getSubExpr); + PASS_THROUGH_REFERENCE(DifferentiableFunctionExtractOriginal, getSubExpr); + PASS_THROUGH_REFERENCE(LinearFunctionExtractOriginal, getSubExpr); + PASS_THROUGH_REFERENCE(LinearToDifferentiableFunction, getSubExpr); PASS_THROUGH_REFERENCE(BridgeToObjC, getSubExpr); PASS_THROUGH_REFERENCE(BridgeFromObjC, getSubExpr); PASS_THROUGH_REFERENCE(ConditionalBridgeFromObjC, getSubExpr); @@ -667,6 +672,11 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::PointerToPointer: case ExprKind::ForeignObjectConversion: case ExprKind::UnevaluatedInstance: + case ExprKind::DifferentiableFunction: + case ExprKind::LinearFunction: + case ExprKind::DifferentiableFunctionExtractOriginal: + case ExprKind::LinearFunctionExtractOriginal: + case ExprKind::LinearToDifferentiableFunction: case ExprKind::EnumIsCase: case ExprKind::ConditionalBridgeFromObjC: case ExprKind::BridgeFromObjC: diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index ef5a03d150626..4428fdad3da80 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -5070,6 +5070,50 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker { return Action::Continue; } + // Infer requirements from `@differentiable` or `@differentiable(linear)` + // function types. + // For all non-`@noDerivative` parameter and result types: + // - `@differentiable`: add `T: Differentiable` requirement. + // - `@differentiable(linear)`: add + // `T: Differentiable`, `T == T.TangentVector` requirements. + if (auto *fnTy = ty->getAs()) { + auto &ctx = Builder.getASTContext(); + auto *differentiableProtocol = + ctx.getProtocol(KnownProtocolKind::Differentiable); + if (differentiableProtocol && fnTy->isDifferentiable()) { + auto addConformanceConstraint = [&](Type type, ProtocolDecl *protocol) { + Requirement req(RequirementKind::Conformance, type, + protocol->getDeclaredType()); + Builder.addRequirement(req, source, nullptr); + }; + auto addSameTypeConstraint = [&](Type firstType, + AssociatedTypeDecl *assocType) { + auto *protocol = assocType->getProtocol(); + auto conf = Builder.lookupConformance(CanType(), firstType, protocol); + auto secondType = conf.getAssociatedType( + firstType, assocType->getDeclaredInterfaceType()); + Requirement req(RequirementKind::SameType, firstType, secondType); + Builder.addRequirement(req, source, nullptr); + }; + auto *tangentVectorAssocType = + differentiableProtocol->getAssociatedType(ctx.Id_TangentVector); + auto addRequirements = [&](Type type, bool isLinear) { + addConformanceConstraint(type, differentiableProtocol); + if (isLinear) + addSameTypeConstraint(type, tangentVectorAssocType); + }; + auto constrainParametersAndResult = [&](bool isLinear) { + for (auto ¶m : fnTy->getParams()) + if (!param.isNoDerivative()) + addRequirements(param.getPlainType(), isLinear); + addRequirements(fnTy->getResult(), isLinear); + }; + // Add requirements. + constrainParametersAndResult(fnTy->getDifferentiabilityKind() == + DifferentiabilityKind::Linear); + } + } + if (!ty->isSpecialized()) return Action::Continue; diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 6339c0891925a..0ad2ed67e3424 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -2068,9 +2068,10 @@ SPIGroupsRequest::evaluate(Evaluator &evaluator, const Decl *decl) const { // Then in the extended nominal type. if (auto extension = dyn_cast(decl)) { - auto extended = extension->getExtendedNominal(); - auto extSPIs = extended->getSPIGroups(); - if (!extSPIs.empty()) return extSPIs; + if (auto extended = extension->getExtendedNominal()) { + auto extSPIs = extended->getSPIGroups(); + if (!extSPIs.empty()) return extSPIs; + } } // And finally in the parent context. diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 84626c26178cc..fdff7adbdefff 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -1327,16 +1327,14 @@ NominalTypeDecl::getSatisfiedProtocolRequirementsForMember( } SmallVector -DeclContext::getLocalProtocols( - ConformanceLookupKind lookupKind, - SmallVectorImpl *diagnostics) const -{ +DeclContext::getLocalProtocols(ConformanceLookupKind lookupKind) const { SmallVector result; // Dig out the nominal type. NominalTypeDecl *nominal = getSelfNominalTypeDecl(); - if (!nominal) + if (!nominal) { return result; + } // Update to record all potential conformances. nominal->prepareConformanceTable(); @@ -1346,28 +1344,29 @@ DeclContext::getLocalProtocols( lookupKind, &result, nullptr, - diagnostics); + nullptr); return result; } SmallVector -DeclContext::getLocalConformances( - ConformanceLookupKind lookupKind, - SmallVectorImpl *diagnostics) const -{ +DeclContext::getLocalConformances(ConformanceLookupKind lookupKind) const { SmallVector result; // Dig out the nominal type. NominalTypeDecl *nominal = getSelfNominalTypeDecl(); - if (!nominal) + if (!nominal) { return result; + } // Protocols only have self-conformances. if (auto protocol = dyn_cast(nominal)) { - if (protocol->requiresSelfConformanceWitnessTable()) - return { protocol->getASTContext().getSelfConformance(protocol) }; - return { }; + if (protocol->requiresSelfConformanceWitnessTable()) { + return SmallVector{ + protocol->getASTContext().getSelfConformance(protocol) + }; + } + return SmallVector(); } // Update to record all potential conformances. @@ -1378,7 +1377,35 @@ DeclContext::getLocalConformances( lookupKind, nullptr, &result, - diagnostics); + nullptr); + + return result; +} + +SmallVector +DeclContext::takeConformanceDiagnostics() const { + SmallVector result; + + // Dig out the nominal type. + NominalTypeDecl *nominal = getSelfNominalTypeDecl(); + if (!nominal) { + return { }; + } + + // Protocols are not subject to the checks for supersession. + if (isa(nominal)) { + return { }; + } + + // Update to record all potential conformances. + nominal->prepareConformanceTable(); + nominal->ConformanceTable->lookupConformances( + nominal, + const_cast(this), + ConformanceLookupKind::All, + nullptr, + nullptr, + &result); return result; } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 032fed0c2b9af..840d039f4a0fa 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -5066,7 +5066,8 @@ TypeBase::getAutoDiffTangentSpace(LookupConformanceFn lookupConformance) { // `TangentVector` associated type. auto *differentiableProtocol = ctx.getProtocol(KnownProtocolKind::Differentiable); - assert(differentiableProtocol && "`Differentiable` protocol not found"); + if (!differentiableProtocol) + return cache(None); auto associatedTypeLookup = differentiableProtocol->lookupDirect(ctx.Id_TangentVector); assert(associatedTypeLookup.size() == 1); diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 0b62510c2c516..6c39e4b72c701 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -1113,8 +1113,7 @@ namespace { void visitConformances(DeclContext *dc) { llvm::SmallSetVector protocols; for (auto conformance : dc->getLocalConformances( - ConformanceLookupKind::OnlyExplicit, - nullptr)) { + ConformanceLookupKind::OnlyExplicit)) { ProtocolDecl *proto = conformance->getProtocol(); getObjCProtocols(proto, protocols); } diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 81a73903bfe8e..28322a3957e5d 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -889,7 +889,7 @@ IRGenModule::getConstantReferenceForProtocolDescriptor(ProtocolDecl *proto) { void IRGenModule::addLazyConformances(DeclContext *dc) { for (const ProtocolConformance *conf : - dc->getLocalConformances(ConformanceLookupKind::All, nullptr)) { + dc->getLocalConformances(ConformanceLookupKind::All)) { IRGen.addLazyWitnessTable(conf); } } diff --git a/lib/SIL/OwnershipUtils.cpp b/lib/SIL/OwnershipUtils.cpp index 23dfe8e50e975..0d9e02bd1fcdc 100644 --- a/lib/SIL/OwnershipUtils.cpp +++ b/lib/SIL/OwnershipUtils.cpp @@ -31,6 +31,7 @@ bool swift::isOwnershipForwardingValueKind(SILNodeKind kind) { case SILNodeKind::StructInst: case SILNodeKind::EnumInst: case SILNodeKind::DifferentiableFunctionInst: + case SILNodeKind::LinearFunctionInst: case SILNodeKind::OpenExistentialRefInst: case SILNodeKind::UpcastInst: case SILNodeKind::UncheckedRefCastInst: @@ -60,6 +61,7 @@ bool swift::isGuaranteedForwardingValueKind(SILNodeKind kind) { case SILNodeKind::TupleExtractInst: case SILNodeKind::StructExtractInst: case SILNodeKind::DifferentiableFunctionExtractInst: + case SILNodeKind::LinearFunctionExtractInst: case SILNodeKind::OpenExistentialValueInst: case SILNodeKind::OpenExistentialBoxValueInst: return true; diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index edfa30920ab94..e9bd193e4f4b2 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -531,6 +531,16 @@ namespace { RValue visitTapExpr(TapExpr *E, SGFContext C); RValue visitDefaultArgumentExpr(DefaultArgumentExpr *E, SGFContext C); RValue visitErrorExpr(ErrorExpr *E, SGFContext C); + + RValue visitDifferentiableFunctionExpr(DifferentiableFunctionExpr *E, + SGFContext C); + RValue visitLinearFunctionExpr(LinearFunctionExpr *E, SGFContext C); + RValue visitDifferentiableFunctionExtractOriginalExpr( + DifferentiableFunctionExtractOriginalExpr *E, SGFContext C); + RValue visitLinearFunctionExtractOriginalExpr( + LinearFunctionExtractOriginalExpr *E, SGFContext C); + RValue visitLinearToDifferentiableFunctionExpr( + LinearToDifferentiableFunctionExpr *E, SGFContext C); }; } // end anonymous namespace @@ -5461,6 +5471,51 @@ RValue RValueEmitter::visitUnevaluatedInstanceExpr(UnevaluatedInstanceExpr *E, llvm_unreachable("unevaluated_instance expression can never be evaluated"); } +RValue RValueEmitter::visitDifferentiableFunctionExpr( + DifferentiableFunctionExpr *E, SGFContext C) { + auto origFunc = SGF.emitRValueAsSingleValue(E->getSubExpr()); + auto destTy = SGF.getLoweredType(E->getType()).castTo(); + auto *diffFunc = SGF.B.createDifferentiableFunction( + E, destTy->getDifferentiabilityParameterIndices(), origFunc.forward(SGF)); + return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(diffFunc)); +} + +RValue RValueEmitter::visitLinearFunctionExpr( + LinearFunctionExpr *E, SGFContext C) { + auto origFunc = SGF.emitRValueAsSingleValue(E->getSubExpr()); + auto destTy = SGF.getLoweredType(E->getType()).castTo(); + auto *diffFunc = SGF.B.createLinearFunction( + E, destTy->getDifferentiabilityParameterIndices(), origFunc.forward(SGF)); + return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(diffFunc)); +} + +RValue RValueEmitter::visitDifferentiableFunctionExtractOriginalExpr( + DifferentiableFunctionExtractOriginalExpr *E, SGFContext C) { + auto diffFunc = SGF.emitRValueAsSingleValue(E->getSubExpr()); + auto borrowedDiffFunc = diffFunc.borrow(SGF, E); + auto *borrowedOrigFunc = SGF.B.createDifferentiableFunctionExtractOriginal( + E, borrowedDiffFunc.getValue()); + auto ownedOrigFunc = SGF.B.emitCopyValueOperation(E, borrowedOrigFunc); + return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(ownedOrigFunc)); +} + +RValue RValueEmitter::visitLinearFunctionExtractOriginalExpr( + LinearFunctionExtractOriginalExpr *E, SGFContext C) { + auto diffFunc = SGF.emitRValueAsSingleValue(E->getSubExpr()); + auto borrowedDiffFunc = diffFunc.borrow(SGF, E); + auto *borrowedOrigFunc = SGF.B.createLinearFunctionExtract( + E, LinearDifferentiableFunctionTypeComponent::Original, + borrowedDiffFunc.getValue()); + auto ownedOrigFunc = SGF.B.emitCopyValueOperation(E, borrowedOrigFunc); + return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(ownedOrigFunc)); +} + +RValue RValueEmitter::visitLinearToDifferentiableFunctionExpr( + LinearToDifferentiableFunctionExpr *E, SGFContext C) { + // TODO: Implement this. + llvm_unreachable("Unsupported!"); +} + RValue RValueEmitter::visitTapExpr(TapExpr *E, SGFContext C) { // This implementation is not very robust; if TapExpr were to ever become // user-accessible (as some sort of "with" statement), it should probably diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 3f19296f7478d..7338d1d18132f 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -1028,7 +1028,7 @@ class SILGenType : public TypeMemberVisitor { // Emit witness tables for conformances of concrete types. Protocol types // are existential and do not have witness tables. for (auto *conformance : theType->getLocalConformances( - ConformanceLookupKind::NonInherited, nullptr)) { + ConformanceLookupKind::NonInherited)) { if (conformance->isComplete()) { if (auto *normal = dyn_cast(conformance)) SGM.getWitnessTable(normal); @@ -1152,8 +1152,7 @@ class SILGenExtension : public TypeMemberVisitor { // Emit witness tables for protocol conformances introduced by the // extension. for (auto *conformance : e->getLocalConformances( - ConformanceLookupKind::All, - nullptr)) { + ConformanceLookupKind::All)) { if (conformance->isComplete()) { if (auto *normal =dyn_cast(conformance)) SGM.getWitnessTable(normal); diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index f44e1bb56f573..e66b4ff69b015 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -356,6 +356,9 @@ void addSSAPasses(SILPassPipelinePlan &P, OptimizationLevelKind OpLevel) { } P.addPerformanceConstantPropagation(); + // Remove redundant arguments right before CSE and DCE, so that CSE and DCE + // can cleanup redundant and dead instructions. + P.addRedundantPhiElimination(); P.addCSE(); P.addDCE(); diff --git a/lib/SILOptimizer/Transforms/CMakeLists.txt b/lib/SILOptimizer/Transforms/CMakeLists.txt index 1bc1faac56742..484d4280bf447 100644 --- a/lib/SILOptimizer/Transforms/CMakeLists.txt +++ b/lib/SILOptimizer/Transforms/CMakeLists.txt @@ -24,6 +24,7 @@ silopt_register_sources( PerformanceInliner.cpp RedundantLoadElimination.cpp RedundantOverflowCheckRemoval.cpp + RedundantPhiElimination.cpp ReleaseDevirtualizer.cpp SemanticARCOpts.cpp SILCodeMotion.cpp diff --git a/lib/SILOptimizer/Transforms/RedundantPhiElimination.cpp b/lib/SILOptimizer/Transforms/RedundantPhiElimination.cpp new file mode 100644 index 0000000000000..66a365eb9009e --- /dev/null +++ b/lib/SILOptimizer/Transforms/RedundantPhiElimination.cpp @@ -0,0 +1,201 @@ +//===--- RedundantPhiElimination.cpp - Remove redundant phi arguments -----===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This pass eliminates redundant basic block arguments. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-optimize-block-arguments" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SIL/SILBasicBlock.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "llvm/Support/Debug.h" + +using namespace swift; + +namespace { + +/// Removes redundant basic block phi-arguments. +/// +/// RedundantPhiEliminationPass eliminates block arguments which have +/// the same value as other arguments of the same block. This also works with +/// cycles, like two equivalent loop induction variables. Such patterns are +/// generated e.g. when using stdlib's enumerated() on Array. +/// +/// \code +/// preheader: +/// br bb1(%initval, %initval) +/// header(%phi1, %phi2): +/// %next1 = builtin "add" (%phi1, %one) +/// %next2 = builtin "add" (%phi2, %one) +/// cond_br %loopcond, header(%next1, %next2), exit +/// exit: +/// \endcode +/// +/// is replaced with +/// +/// \code +/// preheader: +/// br bb1(%initval) +/// header(%phi1): +/// %next1 = builtin "add" (%phi1, %one) +/// %next2 = builtin "add" (%phi1, %one) // dead: will be cleaned-up later +/// cond_br %loopcond, header(%next1), exit +/// exit: +/// \endcode +/// +/// Any remaining dead or "trivially" equivalent instructions will then be +/// cleaned-up by DCE and CSE, respectively. +/// +/// RedundantPhiEliminationPass is not part of SimplifyCFG because +/// * no other SimplifyCFG optimization depends on it. +/// * compile time: it doesn't need to run every time SimplifyCFG runs. +/// +class RedundantPhiEliminationPass : public SILFunctionTransform { +public: + RedundantPhiEliminationPass() {} + + void run() override; + +private: + bool optimizeArgs(SILBasicBlock *block); + + bool valuesAreEqual(SILValue val1, SILValue val2); +}; + +void RedundantPhiEliminationPass::run() { + SILFunction *F = getFunction(); + if (!F->shouldOptimize()) + return; + + LLVM_DEBUG(llvm::dbgs() << "*** RedundantPhiElimination on function: " + << F->getName() << " ***\n"); + + bool changed = false; + for (SILBasicBlock &block : *getFunction()) { + changed |= optimizeArgs(&block); + } + + if (changed) { + invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); + } +} + +bool RedundantPhiEliminationPass::optimizeArgs(SILBasicBlock *block) { + // Avoid running into quadratic behavior for blocks which have many arguments. + // This is seldom, anyway. + unsigned maxArgumentCombinations = 48; + + bool changed = false; + unsigned numArgumentCombinations = 0; + for (unsigned arg1Idx = 0; arg1Idx < block->getNumArguments(); ++arg1Idx) { + for (unsigned arg2Idx = arg1Idx + 1; arg2Idx < block->getNumArguments();) { + if (++numArgumentCombinations > maxArgumentCombinations) + return changed; + + SILArgument *arg1 = block->getArgument(arg1Idx); + SILArgument *arg2 = block->getArgument(arg2Idx); + if (!arg1->isPhiArgument() || !arg2->isPhiArgument()) + continue; + + if (valuesAreEqual(arg1, arg2)) { + arg2->replaceAllUsesWith(arg1); + erasePhiArgument(block, arg2Idx); + changed = true; + } else { + ++arg2Idx; + } + } + } + return changed; +} + +bool RedundantPhiEliminationPass::valuesAreEqual(SILValue val1, SILValue val2) { + + // Again, avoid running into quadratic behavior in case of cycles or long + // chains of instructions. This limit is practically never exceeded. + unsigned maxNumberOfChecks = 16; + + SmallVector, 8> workList; + llvm::SmallSet, 16> handled; + + workList.push_back({val1, val2}); + handled.insert({val1, val2}); + + while (!workList.empty()) { + + if (handled.size() > maxNumberOfChecks) + return false; + + auto valuePair = workList.pop_back_val(); + SILValue val1 = valuePair.first; + SILValue val2 = valuePair.second; + + // The trivial case. + if (val1 == val2) + continue; + + if (val1->getKind() != val2->getKind()) + return false; + + if (auto *arg1 = dyn_cast(val1)) { + auto *arg2 = cast(val2); + SILBasicBlock *argBlock = arg1->getParent(); + if (argBlock != arg2->getParent()) + return false; + if (arg1->getType() != arg2->getType()) + return false; + + // All incoming phi values must be equal. + for (SILBasicBlock *pred : argBlock->getPredecessorBlocks()) { + SILValue incoming1 = arg1->getIncomingPhiValue(pred); + SILValue incoming2 = arg2->getIncomingPhiValue(pred); + if (!incoming1 || !incoming2) + return false; + + if (handled.insert({incoming1, incoming2}).second) + workList.push_back({incoming1, incoming2}); + } + continue; + } + + if (auto *inst1 = dyn_cast(val1)) { + // Bail if the instructions have any side effects. + if (inst1->getMemoryBehavior() != SILInstruction::MemoryBehavior::None) + return false; + + auto *inst2 = cast(val2); + + // Compare the operands by putting them on the worklist. + if (!inst1->isIdenticalTo(inst2, [&](SILValue op1, SILValue op2) { + if (handled.insert({op1, op2}).second) + workList.push_back({op1, op2}); + return true; + })) { + return false; + } + continue; + } + + return false; + } + + return true; +} + +} // end anonymous namespace + +SILTransform *swift::createRedundantPhiElimination() { + return new RedundantPhiEliminationPass(); +} diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 130e3581a3697..2d212b0c2f9f7 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5931,6 +5931,80 @@ getSemanticExprForDeclOrMemberRef(Expr *expr) { return semanticExpr; } +static void +maybeDiagnoseUnsupportedDifferentiableConversion(ConstraintSystem &cs, + Expr *expr, + AnyFunctionType *toType) { + ASTContext &ctx = cs.getASTContext(); + Type fromType = cs.getType(expr); + auto fromFnType = fromType->getAs(); + auto isToTypeLinear = + toType->getDifferentiabilityKind() == DifferentiabilityKind::Linear; + // Conversion from a `@differentiable` function to a `@differentiable(linear)` + // function is not allowed, because the from-expression will never be a + // closure expression or a declaration/member reference. + if (fromFnType->getDifferentiabilityKind() == DifferentiabilityKind::Normal && + toType->getDifferentiabilityKind() == DifferentiabilityKind::Linear) { + ctx.Diags.diagnose(expr->getLoc(), + diag::invalid_differentiable_function_conversion_expr, + isToTypeLinear); + return; + } + // Conversion from a non-`@differentiable` function to a `@differentiable` is + // only allowed from a closure expression or a declaration/member reference. + if (!fromFnType->isDifferentiable() && toType->isDifferentiable()) { + std::function maybeDiagnoseFunctionRef; + maybeDiagnoseFunctionRef = [&](Expr *semanticExpr) { + if (auto *capture = dyn_cast(semanticExpr)) + semanticExpr = capture->getClosureBody(); + if (isa(semanticExpr)) return; + if (auto *declRef = dyn_cast(semanticExpr)) { + if (isa(declRef->getDecl())) return; + // If the referenced decl is a function parameter, the user may want + // to change the declaration to be a '@differentiable' closure. Emit a + // note with a fix-it. + if (auto *paramDecl = dyn_cast(declRef->getDecl())) { + ctx.Diags.diagnose( + expr->getLoc(), + diag::invalid_differentiable_function_conversion_expr, + isToTypeLinear); + if (paramDecl->getType()->is()) { + auto *typeRepr = paramDecl->getTypeRepr(); + while (auto *attributed = dyn_cast(typeRepr)) + typeRepr = attributed->getTypeRepr(); + std::string attributeString = "@differentiable"; + if (isToTypeLinear) + attributeString += "(linear)"; + auto *funcTypeRepr = cast(typeRepr); + auto paramListLoc = funcTypeRepr->getArgsTypeRepr()->getStartLoc(); + ctx.Diags.diagnose(paramDecl->getLoc(), + diag::invalid_differentiable_function_conversion_parameter, + attributeString) + .highlight(paramDecl->getTypeRepr()->getSourceRange()) + .fixItInsert(paramListLoc, attributeString + " "); + } + return; + } + } else if (auto *memberRef = dyn_cast(semanticExpr)) { + if (isa(memberRef->getMember().getDecl())) return; + } else if (auto *dotSyntaxCall = + dyn_cast(semanticExpr)) { + Expr *fnExpr = dotSyntaxCall->getFn()->getSemanticsProvidingExpr(); + while (auto *autoclosureExpr = dyn_cast(fnExpr)) + if (auto *unwrappedFnExpr = autoclosureExpr->getUnwrappedCurryThunkExpr()) + fnExpr = unwrappedFnExpr; + // Recurse on the function expression. + maybeDiagnoseFunctionRef(fnExpr); + return; + } + ctx.Diags.diagnose(expr->getLoc(), + diag::invalid_differentiable_function_conversion_expr, + isToTypeLinear); + }; + maybeDiagnoseFunctionRef(getSemanticExprForDeclOrMemberRef(expr)); + } +} + static void maybeDiagnoseUnsupportedFunctionConversion(ConstraintSystem &cs, Expr *expr, AnyFunctionType *toType) { @@ -6570,6 +6644,63 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, InitializerKind::DefaultArgument); auto toEI = toFunc->getExtInfo(); assert(toType->is()); + + // Handle implicit conversions between non-@differentiable and + // @differentiable functions. + { + auto fromEI = fromFunc->getExtInfo(); + auto isFromDifferentiable = fromEI.isDifferentiable(); + auto isToDifferentiable = toEI.isDifferentiable(); + // Handle implicit conversion from @differentiable. + if (isFromDifferentiable && !isToDifferentiable) { + fromFunc = fromFunc->getWithoutDifferentiability() + ->castTo(); + switch (fromEI.getDifferentiabilityKind()) { + case DifferentiabilityKind::Normal: + expr = cs.cacheType(new (ctx) + DifferentiableFunctionExtractOriginalExpr(expr, fromFunc)); + break; + case DifferentiabilityKind::Linear: + expr = cs.cacheType(new (ctx) + LinearFunctionExtractOriginalExpr(expr, fromFunc)); + break; + case DifferentiabilityKind::NonDifferentiable: + llvm_unreachable("Cannot be NonDifferentiable"); + } + } + // Handle implicit conversion from @differentiable(linear) to + // @differentiable. + else if (fromEI.getDifferentiabilityKind() == + DifferentiabilityKind::Linear && + toEI.getDifferentiabilityKind() == DifferentiabilityKind::Normal) { + // TODO(TF-908): Create a `LinearToDifferentiableFunctionExpr` and SILGen + // it as thunk application. Remove the diagnostic. + ctx.Diags.diagnose(expr->getLoc(), + diag::unsupported_linear_to_differentiable_conversion); + } + // Handle implicit conversion from non-@differentiable to @differentiable. + maybeDiagnoseUnsupportedDifferentiableConversion(cs, expr, toFunc); + if (!isFromDifferentiable && isToDifferentiable) { + auto newEI = + fromEI.withDifferentiabilityKind(toEI.getDifferentiabilityKind()); + fromFunc = FunctionType::get(toFunc->getParams(), fromFunc->getResult()) + ->withExtInfo(newEI) + ->castTo(); + switch (toEI.getDifferentiabilityKind()) { + case DifferentiabilityKind::Normal: + expr = cs.cacheType(new (ctx) + DifferentiableFunctionExpr(expr, fromFunc)); + break; + case DifferentiabilityKind::Linear: + expr = cs.cacheType(new (ctx) + LinearFunctionExpr(expr, fromFunc)); + break; + case DifferentiabilityKind::NonDifferentiable: + llvm_unreachable("Cannot be NonDifferentiable"); + } + } + } + // If we have a ClosureExpr, then we can safely propagate the 'no escape' // bit to the closure without invalidating prior analysis. auto fromEI = fromFunc->getExtInfo(); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 40cd26c18bc06..1228cd95c04d9 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -431,24 +431,24 @@ matchCallArguments(SmallVectorImpl &args, // If we have a trailing closure, it maps to the last parameter. if (hasTrailingClosure && numParams > 0) { + unsigned lastParamIdx = numParams - 1; + bool lastAcceptsTrailingClosure = + acceptsTrailingClosure(params[lastParamIdx]); + // If the last parameter is defaulted, this might be // an attempt to use a trailing closure with previous // parameter that accepts a function type e.g. // // func foo(_: () -> Int, _ x: Int = 0) {} // foo { 42 } - bool lastAcceptsTrailingClosure = false; - unsigned lastParamIdx = numParams - 1; - for (unsigned i : indices(params)) { - unsigned idx = numParams - 1 - i; - if (acceptsTrailingClosure(params[idx])) { + if (!lastAcceptsTrailingClosure && numParams > 1 && + paramInfo.hasDefaultArgument(lastParamIdx)) { + auto paramType = params[lastParamIdx - 1].getPlainType(); + // If the parameter before defaulted last accepts. + if (paramType->is()) { lastAcceptsTrailingClosure = true; - lastParamIdx = idx; - break; + lastParamIdx -= 1; } - if (paramInfo.hasDefaultArgument(idx)) - continue; - break; } bool isExtraClosure = false; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index da4f908c50652..175652ab3090a 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -5066,6 +5066,12 @@ diagnoseMissingAppendInterpolationMethod(NominalTypeDecl *typeDecl) { } } +llvm::Expected> +LookupAllConformancesInContextRequest::evaluate( + Evaluator &eval, const DeclContext *DC) const { + return DC->getLocalConformances(ConformanceLookupKind::All); +} + void TypeChecker::checkConformancesInContext(DeclContext *dc, IterableDeclContext *idc) { // For anything imported from Clang, lazily check conformances. @@ -5092,9 +5098,9 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc, tracker = SF->getReferencedNameTracker(); // Check each of the conformances associated with this context. - SmallVector diagnostics; - auto conformances = dc->getLocalConformances(ConformanceLookupKind::All, - &diagnostics); + auto conformances = + evaluateOrDefault(dc->getASTContext().evaluator, + LookupAllConformancesInContextRequest{dc}, {}); // The conformance checker bundle that checks all conformances in the context. auto &Context = dc->getASTContext(); @@ -5151,7 +5157,7 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc, groupChecker.getUnsatisfiedRequirements().end()); // Diagnose any conflicts attributed to this declaration context. - for (const auto &diag : diagnostics) { + for (const auto &diag : dc->takeConformanceDiagnostics()) { // Figure out the declaration of the existing conformance. Decl *existingDecl = dyn_cast(diag.ExistingDC); if (!existingDecl) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 8a1028633cf49..fb4c2bb0d5769 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1865,6 +1865,11 @@ namespace { Type resolveOpaqueReturnType(TypeRepr *repr, StringRef mangledName, unsigned ordinal, TypeResolutionOptions options); + + /// Returns true if the given type conforms to `Differentiable` in the + /// module of `DC`. If `tangentVectorEqualsSelf` is true, returns true iff + /// the given type additionally satisfies `Self == Self.TangentVector`. + bool isDifferentiable(Type type, bool tangentVectorEqualsSelf = false); }; } // end anonymous namespace @@ -2256,16 +2261,16 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, } } - if (attrs.has(TAK_differentiable) && - !Context.LangOpts.EnableExperimentalDifferentiableProgramming) { - diagnoseInvalid(repr, attrs.getLoc(TAK_differentiable), - diag::experimental_differentiable_programming_disabled); - } - DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable; if (attrs.has(TAK_differentiable)) { - diffKind = attrs.linear ? DifferentiabilityKind::Linear - : DifferentiabilityKind::Normal; + if (Context.LangOpts.EnableExperimentalDifferentiableProgramming) { + diffKind = attrs.linear ? DifferentiabilityKind::Linear + : DifferentiabilityKind::Normal; + } else { + diagnoseInvalid( + repr, attrs.getLoc(TAK_differentiable), + diag::experimental_differentiable_programming_disabled); + } } // Resolve the function type directly with these attributes. @@ -2304,16 +2309,16 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, } } - if (attrs.has(TAK_differentiable) && - !Context.LangOpts.EnableExperimentalDifferentiableProgramming) { - diagnoseInvalid(repr, attrs.getLoc(TAK_differentiable), - diag::experimental_differentiable_programming_disabled); - } - DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable; if (attrs.has(TAK_differentiable)) { - diffKind = attrs.linear ? DifferentiabilityKind::Linear - : DifferentiabilityKind::Normal; + if (Context.LangOpts.EnableExperimentalDifferentiableProgramming) { + diffKind = attrs.linear ? DifferentiabilityKind::Linear + : DifferentiabilityKind::Normal; + } else { + diagnoseInvalid( + repr, attrs.getLoc(TAK_differentiable), + diag::experimental_differentiable_programming_disabled); + } } ty = resolveASTFunctionType(fnRepr, options, rep, /*noescape=*/false, @@ -2588,6 +2593,39 @@ bool TypeResolver::resolveASTFunctionTypeParams( elements.emplace_back(ty, Identifier(), paramFlags); } + // All non-`@noDerivative` parameters of `@differentiable` and + // `@differentiable(linear)` function types must be differentiable. + if (diffKind != DifferentiabilityKind::NonDifferentiable && + resolution.getStage() != TypeResolutionStage::Structural) { + bool isLinear = diffKind == DifferentiabilityKind::Linear; + // Emit `@noDerivative` fixit only if there is at least one valid + // differentiability/linearity parameter. Otherwise, adding `@noDerivative` + // produces an ill-formed function type. + auto hasValidDifferentiabilityParam = + llvm::find_if(elements, [&](AnyFunctionType::Param param) { + if (param.isNoDerivative()) + return false; + return isDifferentiable(param.getPlainType(), + /*tangentVectorEqualsSelf*/ isLinear); + }) != elements.end(); + for (unsigned i = 0, end = inputRepr->getNumElements(); i != end; ++i) { + auto *eltTypeRepr = inputRepr->getElementType(i); + auto param = elements[i]; + if (param.isNoDerivative()) + continue; + auto paramType = param.getPlainType(); + if (isDifferentiable(paramType, /*tangentVectorEqualsSelf*/ isLinear)) + continue; + auto paramTypeString = paramType->getString(); + auto diagnostic = + diagnose(eltTypeRepr->getLoc(), + diag::differentiable_function_type_invalid_parameter, + paramTypeString, isLinear, hasValidDifferentiabilityParam); + if (hasValidDifferentiabilityParam) + diagnostic.fixItInsert(eltTypeRepr->getLoc(), "@noDerivative "); + } + } + return false; } @@ -2720,10 +2758,37 @@ Type TypeResolver::resolveASTFunctionType( case AnyFunctionType::Representation::Swift: break; } - + + // `@differentiable` and `@differentiable(linear)` function types must return + // a differentiable type. + if (extInfo.isDifferentiable() && + resolution.getStage() != TypeResolutionStage::Structural) { + bool isLinear = diffKind == DifferentiabilityKind::Linear; + if (!isDifferentiable(outputTy, /*tangentVectorEqualsSelf*/ isLinear)) { + diagnose(repr->getResultTypeRepr()->getLoc(), + diag::differentiable_function_type_invalid_result, + outputTy->getString(), isLinear) + .highlight(repr->getResultTypeRepr()->getSourceRange()); + } + } + return fnTy; } +bool TypeResolver::isDifferentiable(Type type, bool tangentVectorEqualsSelf) { + if (resolution.getStage() != TypeResolutionStage::Contextual) + type = DC->mapTypeIntoContext(type); + auto tanSpace = type->getAutoDiffTangentSpace( + LookUpConformanceInModule(DC->getParentModule())); + if (!tanSpace) + return false; + // If no `Self == Self.TangentVector` requirement, return true. + if (!tangentVectorEqualsSelf) + return true; + // Otherwise, return true if `Self == Self.TangentVector`. + return type->getCanonicalType() == tanSpace->getCanonicalType(); +} + Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, TypeResolutionOptions options) { // Resolve the field types. diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 2caa73c3888e3..a091fafb0ea35 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2839,7 +2839,7 @@ class Serializer::DeclSerializer : public DeclVisitor { extendedType = extendedType->getCanonicalType(); auto conformances = extension->getLocalConformances( - ConformanceLookupKind::All, nullptr); + ConformanceLookupKind::All); SmallVector inheritedAndDependencyTypes; for (auto inherited : extension->getInherited()) { @@ -3073,7 +3073,7 @@ class Serializer::DeclSerializer : public DeclVisitor { auto contextID = S.addDeclContextRef(theStruct->getDeclContext()); auto conformances = theStruct->getLocalConformances( - ConformanceLookupKind::All, nullptr); + ConformanceLookupKind::All); SmallVector inheritedAndDependencyTypes; for (auto inherited : theStruct->getInherited()) { @@ -3118,7 +3118,7 @@ class Serializer::DeclSerializer : public DeclVisitor { auto contextID = S.addDeclContextRef(theEnum->getDeclContext()); auto conformances = theEnum->getLocalConformances( - ConformanceLookupKind::All, nullptr); + ConformanceLookupKind::All); SmallVector inheritedAndDependencyTypes; for (auto inherited : theEnum->getInherited()) { @@ -3176,7 +3176,7 @@ class Serializer::DeclSerializer : public DeclVisitor { auto contextID = S.addDeclContextRef(theClass->getDeclContext()); auto conformances = theClass->getLocalConformances( - ConformanceLookupKind::NonInherited, nullptr); + ConformanceLookupKind::NonInherited); SmallVector inheritedAndDependencyTypes; for (auto inherited : theClass->getInherited()) { diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index 29d2a672522e5..b9465e745a301 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -56,28 +56,16 @@ using namespace llvm::yaml; using StringSet = llvm::StringSet<>; using SymbolKind = llvm::MachO::SymbolKind; -static constexpr StringLiteral ObjC2ClassNamePrefix = "_OBJC_CLASS_$_"; -static constexpr StringLiteral ObjC2MetaClassNamePrefix = "_OBJC_METACLASS_$_"; - static bool isGlobalOrStaticVar(VarDecl *VD) { return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext(); } -// If a symbol is implied, we don't need to emit it explictly into the tbd file. -// e.g. When a symbol is in the `objc-classes` section in a tbd file, a additional -// symbol with `_OBJC_CLASS_$_` is implied. -static bool isSymbolImplied(StringRef name) { - return name.startswith(ObjC2ClassNamePrefix) || - name.startswith(ObjC2MetaClassNamePrefix); -} - void TBDGenVisitor::addSymbolInternal(StringRef name, llvm::MachO::SymbolKind kind, bool isLinkerDirective) { if (!isLinkerDirective && Opts.LinkerDirectivesOnly) return; - if (!isSymbolImplied(name)) - Symbols.addSymbol(kind, name, Targets); + Symbols.addSymbol(kind, name, Targets); if (StringSymbols && kind == SymbolKind::GlobalSymbol) { auto isNewValue = StringSymbols->insert(name).second; (void)isNewValue; diff --git a/stdlib/public/Darwin/XCTest/XCTest.swift b/stdlib/public/Darwin/XCTest/XCTest.swift index b046fd547c402..cd383853ab6e1 100644 --- a/stdlib/public/Darwin/XCTest/XCTest.swift +++ b/stdlib/public/Darwin/XCTest/XCTest.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,6 +10,17 @@ // //===----------------------------------------------------------------------===// +// The actual XCTest overlay is not maintained in this repository -- it is +// distributed in Xcode (libXCTestSwiftSupport.dylib), along with +// XCTest.framework itself. +// +// The codebase here builds the obsolete /usr/lib/swift/libswiftXCTest.dylib +// that currently ships in the OS. There is no expectation that that library is +// usable for anything; it only exists to maintain a superficial level of binary +// compatibility with existing apps that happen to link to it by mistake. +// +// rdar://problem/55270944 + @_exported import XCTest // Clang module import CoreGraphics diff --git a/stdlib/public/Darwin/XCTest/XCTestCaseAdditions.mm b/stdlib/public/Darwin/XCTest/XCTestCaseAdditions.mm index fe3e5341e1ca4..8181dd1d58d3d 100644 --- a/stdlib/public/Darwin/XCTest/XCTestCaseAdditions.mm +++ b/stdlib/public/Darwin/XCTest/XCTestCaseAdditions.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,6 +10,17 @@ // //===----------------------------------------------------------------------===// +// The actual XCTest overlay is not maintained in this repository -- it is +// distributed in Xcode (libXCTestSwiftSupport.dylib), along with +// XCTest.framework itself. +// +// The codebase here builds the obsolete /usr/lib/swift/libswiftXCTest.dylib +// that currently ships in the OS. There is no expectation that that library is +// usable for anything; it only exists to maintain a superficial level of binary +// compatibility with existing apps that happen to link to it by mistake. +// +// rdar://problem/55270944 + #import #include "swift/Runtime/Metadata.h" #include "swift/Demangling/Demangle.h" diff --git a/test/AutoDiff/ModuleInterface/differentiation.swift b/test/AutoDiff/ModuleInterface/differentiation.swift index 35ee0f9067891..1d83cd49dc210 100644 --- a/test/AutoDiff/ModuleInterface/differentiation.swift +++ b/test/AutoDiff/ModuleInterface/differentiation.swift @@ -1,6 +1,8 @@ // RUN: %target-swift-frontend -typecheck -emit-module-interface-path %t.swiftinterface -enable-library-evolution -enable-experimental-differentiable-programming %s // RUN: %FileCheck %s < %t.swiftinterface +import _Differentiation + public func a(f: @differentiable (Float) -> Float) {} // CHECK: public func a(f: @differentiable (Swift.Float) -> Swift.Float) diff --git a/test/AutoDiff/SILGen/differentiable_function.swift b/test/AutoDiff/SILGen/differentiable_function.swift index e298eb690a55e..11732ef97fe8c 100644 --- a/test/AutoDiff/SILGen/differentiable_function.swift +++ b/test/AutoDiff/SILGen/differentiable_function.swift @@ -4,6 +4,10 @@ import _Differentiation +//===----------------------------------------------------------------------===// +// Return `@differentiable` function typed values unmodified. +//===----------------------------------------------------------------------===// + @_silgen_name("differentiable") func differentiable(_ fn: @escaping @differentiable (Float) -> Float) -> @differentiable (Float) -> Float { @@ -53,3 +57,71 @@ func linear_noDerivative( // CHECK: [[COPIED_FN:%.*]] = copy_value [[FN]] : $@differentiable(linear) @callee_guaranteed (Float, @noDerivative Float) -> Float // CHECK: return [[COPIED_FN]] : $@differentiable(linear) @callee_guaranteed (Float, @noDerivative Float) -> Float // CHECK: } + +//===----------------------------------------------------------------------===// +// Closure conversion +//===----------------------------------------------------------------------===// + +func thin(x: Float) -> Float { return x } + +func myfunction(_ f: @escaping @differentiable (Float) -> (Float)) -> (Float) -> Float { + // @differentiable functions should be callable. + _ = f(.zero) + return f +} + +func myfunction2(_ f: @escaping @differentiable(linear) (Float) -> (Float)) -> (Float) -> Float { + // @differentiable(linear) functions should be callable. + _ = f(.zero) + return f +} + +var global_f: @differentiable (Float) -> Float = {$0} +var global_f_linear: @differentiable(linear) (Float) -> Float = {$0} + +func calls_global_f() { + _ = global_f(10) + // TODO(TF-900, TF-902): Uncomment the following line to test loading a linear function from memory and direct calls to a linear function. + // _ = global_f_linear(10) +} + +func apply() { + _ = myfunction(thin) + _ = myfunction2(thin) +} + +// CHECK-LABEL: @{{.*}}myfunction{{.*}} +// CHECK: bb0([[DIFF:%.*]] : @guaranteed $@differentiable @callee_guaranteed (Float) -> Float): +// CHECK: [[COPIED_DIFF:%.*]] = copy_value [[DIFF]] : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: [[BORROWED_DIFF:%.*]] = begin_borrow [[COPIED_DIFF]] : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: apply [[BORROWED_DIFF]]({{%.*}}) : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: end_borrow [[BORROWED_DIFF]] : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: destroy_value [[COPIED_DIFF]] : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: [[COPIED_DIFF:%.*]] = copy_value [[DIFF]] : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: [[BORROWED_DIFF:%.*]] = begin_borrow [[COPIED_DIFF]] : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: [[BORROWED_ORIG:%.*]] = differentiable_function_extract [original] [[BORROWED_DIFF]] : $@differentiable @callee_guaranteed (Float) -> Float +// CHECK: [[COPIED_ORIG:%.*]] = copy_value [[BORROWED_ORIG]] : $@callee_guaranteed (Float) -> Float +// CHECK: return [[COPIED_ORIG]] : $@callee_guaranteed (Float) -> Float + +// CHECK-LABEL: @{{.*}}myfunction2{{.*}} +// CHECK: bb0([[LIN:%.*]] : @guaranteed $@differentiable(linear) @callee_guaranteed (Float) -> Float): +// CHECK: [[COPIED_LIN:%.*]] = copy_value [[LIN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: [[BORROWED_LIN:%.*]] = begin_borrow [[COPIED_LIN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: apply [[BORROWED_LIN]]({{%.*}}) : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: end_borrow [[BORROWED_LIN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: [[COPIED_LIN:%.*]] = copy_value [[LIN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: [[BORROWED_LIN:%.*]] = begin_borrow [[COPIED_LIN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: [[BORROWED_ORIG:%.*]] = linear_function_extract [original] [[BORROWED_LIN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: [[COPIED_ORIG:%.*]] = copy_value [[BORROWED_ORIG]] : $@callee_guaranteed (Float) -> Float +// CHECK: end_borrow [[BORROWED_LIN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: destroy_value [[COPIED_LIN]] : $@differentiable(linear) @callee_guaranteed (Float) -> Float +// CHECK: return [[COPIED_ORIG]] : $@callee_guaranteed (Float) -> Float + +// CHECK-LABEL: @{{.*}}apply{{.*}} +// CHECK: [[ORIG:%.*]] = function_ref @{{.*}}thin{{.*}} : $@convention(thin) (Float) -> Float +// CHECK-NEXT: [[ORIG_THICK:%.*]] = thin_to_thick_function [[ORIG]] : $@convention(thin) (Float) -> Float to $@callee_guaranteed (Float) -> Float +// CHECK-NEXT: [[DIFFED:%.*]] = differentiable_function [parameters 0] [[ORIG_THICK]] : $@callee_guaranteed (Float) -> Float +// CHECK: [[ORIG:%.*]] = function_ref @{{.*}}thin{{.*}} : $@convention(thin) (Float) -> Float +// CHECK-NEXT: [[ORIG_THICK:%.*]] = thin_to_thick_function [[ORIG]] : $@convention(thin) (Float) -> Float to $@callee_guaranteed (Float) -> Float +// CHECK-NEXT: [[LIN:%.*]] = linear_function [parameters 0] [[ORIG_THICK]] : $@callee_guaranteed (Float) -> Float + diff --git a/test/AutoDiff/Sema/differentiable_attr_type_checking.swift b/test/AutoDiff/Sema/differentiable_attr_type_checking.swift index 91c512f9ed196..66d787db16710 100644 --- a/test/AutoDiff/Sema/differentiable_attr_type_checking.swift +++ b/test/AutoDiff/Sema/differentiable_attr_type_checking.swift @@ -396,7 +396,7 @@ extension TF_521: Differentiable where T: Differentiable { // expected-note @+1 {{possibly intended match 'TF_521.TangentVector' does not conform to 'AdditiveArithmetic'}} typealias TangentVector = TF_521 } - +// expected-error @+1 {{result type 'TF_521' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} let _: @differentiable(Float, Float) -> TF_521 = { r, i in TF_521(real: r, imaginary: i) } diff --git a/test/AutoDiff/Sema/differentiable_func_type.swift b/test/AutoDiff/Sema/differentiable_func_type.swift index 0515dcc95d027..c4a8a7ec494ed 100644 --- a/test/AutoDiff/Sema/differentiable_func_type.swift +++ b/test/AutoDiff/Sema/differentiable_func_type.swift @@ -1,21 +1,124 @@ // RUN: %target-swift-frontend -enable-experimental-differentiable-programming -typecheck -verify %s +import _Differentiation + +//===----------------------------------------------------------------------===// +// Basic @differentiable function types. +//===----------------------------------------------------------------------===// + // expected-error @+1 {{@differentiable attribute only applies to function types}} let _: @differentiable Float let _: @differentiable (Float) -> Float +let _: @differentiable (Float) throws -> Float + +//===----------------------------------------------------------------------===// +// Type differentiability +//===----------------------------------------------------------------------===// + +struct NonDiffType { var x: Int } + +// FIXME: Properly type-check parameters and the result's differentiability +// expected-error @+1 {{parameter type 'NonDiffType' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +let _: @differentiable (NonDiffType) -> Float + +// Emit `@noDerivative` fixit iff there is at least one valid differentiability parameter. +// expected-error @+1 {{parameter type 'NonDiffType' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'; did you want to add '@noDerivative' to this parameter?}} {{32-32=@noDerivative }} +let _: @differentiable (Float, NonDiffType) -> Float + +// expected-error @+1 {{result type 'NonDiffType' does not conform to 'Differentiable' and satisfy 'NonDiffType == NonDiffType.TangentVector', but the enclosing function type is '@differentiable(linear)'}} +let _: @differentiable(linear) (Float) -> NonDiffType + +// Emit `@noDerivative` fixit iff there is at least one valid linearity parameter. +// expected-error @+1 {{parameter type 'NonDiffType' does not conform to 'Differentiable' and satisfy 'NonDiffType == NonDiffType.TangentVector', but the enclosing function type is '@differentiable(linear)'; did you want to add '@noDerivative' to this parameter?}} {{40-40=@noDerivative }} +let _: @differentiable(linear) (Float, NonDiffType) -> Float + +// expected-error @+1 {{result type 'NonDiffType' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +let _: @differentiable (Float) -> NonDiffType + +// expected-error @+1 {{result type 'NonDiffType' does not conform to 'Differentiable' and satisfy 'NonDiffType == NonDiffType.TangentVector', but the enclosing function type is '@differentiable(linear)'}} +let _: @differentiable(linear) (Float) -> NonDiffType + +let _: @differentiable(linear) (Float) -> Float + +// expected-error @+1 {{result type '@differentiable (U) -> Float' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +func test1(_: @differentiable (T) -> @differentiable (U) -> Float) {} +// expected-error @+1 {{result type '(U) -> Float' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +func test2(_: @differentiable (T) -> (U) -> Float) {} +// expected-error @+2 {{result type 'Int' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +// expected-error @+1 {{result type '@differentiable (U) -> Int' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +func test3(_: @differentiable (T) -> @differentiable (U) -> Int) {} +// expected-error @+1 {{result type '(U) -> Int' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +func test4(_: @differentiable (T) -> (U) -> Int) {} + +//===----------------------------------------------------------------------===// +// Function conversion +//===----------------------------------------------------------------------===// + +/// Function with similar signature as `gradient`, for testing purposes. +func fakeGradient(of f: @differentiable (T) -> U) {} + +func takesOpaqueClosure(f: @escaping (Float) -> Float) { + // expected-note @-1 {{did you mean to take a '@differentiable' closure?}} {{38-38=@differentiable }} + // expected-error @+1 {{a '@differentiable' function can only be formed from a reference to a 'func' or a literal closure}} + fakeGradient(of: f) +} + +let globalAddOne: (Float) -> Float = { $0 + 1 } +// expected-error @+1 {{a '@differentiable' function can only be formed from a reference to a 'func' or a literal closure}} +fakeGradient(of: globalAddOne) + +func someScope() { + let localAddOne: (Float) -> Float = { $0 + 1 } + // expected-error @+1 {{a '@differentiable' function can only be formed from a reference to a 'func' or a literal closure}} + fakeGradient(of: globalAddOne) + // expected-error @+1 {{a '@differentiable' function can only be formed from a reference to a 'func' or a literal closure}} + fakeGradient(of: localAddOne) + // The following case is okay during type checking, but will fail in the AD transform. + fakeGradient { localAddOne($0) } +} + +func addOne(x: Float) -> Float { x + 1 } +fakeGradient(of: addOne) // okay + +extension Float { + static func addOne(x: Float) -> Float { x + 1 } + func addOne(x: Float) -> Float { x + 1 } +} +fakeGradient(of: Float.addOne) // okay +fakeGradient(of: Float(1.0).addOne) // okay + +// TODO(TF-908): Remove this test once linear-to-differentiable conversion is supported. +func linearToDifferentiable(_ f: @escaping @differentiable(linear) (Float) -> Float) { + // expected-error @+1 {{conversion from '@differentiable(linear)' to '@differentiable' is not yet supported}} + _ = f as @differentiable (Float) -> Float +} + +func differentiableToLinear(_ f: @escaping @differentiable (Float) -> Float) { + // expected-error @+1 {{a '@differentiable(linear)' function can only be formed from a reference to a 'func' or a literal closure}} + _ = f as @differentiable(linear) (Float) -> Float +} + +//===----------------------------------------------------------------------===// +// Parameter selection (@noDerivative) +//===----------------------------------------------------------------------===// // expected-error @+1 {{'@noDerivative' may only be used on parameters of '@differentiable' function types}} let _: @noDerivative Float // expected-error @+1 {{'@noDerivative' may only be used on parameters of '@differentiable' function types}} -let _: (Float) -> @noDerivative Float +let _: (@noDerivative Float) -> Float // expected-error @+1 {{'@noDerivative' may only be used on parameters of '@differentiable' function types}} -let _: @differentiable (Float) -> @noDerivative Float +let _: (@noDerivative Float, Float) -> Float + +let _: @differentiable (Float, @noDerivative Float) -> Float // okay // expected-error @+1 {{'@noDerivative' may only be used on parameters of '@differentiable' function types}} -let _: (@noDerivative Float) -> Float +let _: (Float) -> @noDerivative Float + +// expected-error @+1 {{'@noDerivative' may only be used on parameters of '@differentiable' function types}} +let _: @differentiable (Float) -> @noDerivative Float // expected-error @+2 {{'@noDerivative' may only be used on parameters of '@differentiable' function types}} // expected-error @+1 {{'@noDerivative' must not be used on variadic parameters}} @@ -25,3 +128,95 @@ let _: @differentiable (@noDerivative Float, Float) -> Float // expected-error @+1 {{'@noDerivative' must not be used on variadic parameters}} let _: @differentiable (Float, @noDerivative Float...) -> Float + +//===----------------------------------------------------------------------===// +// Inferred conformances +//===----------------------------------------------------------------------===// + +let diffFunc: @differentiable (Float) -> Float +let linearFunc: @differentiable(linear) (Float) -> Float +func inferredConformances(_: @differentiable (T) -> U) {} +func inferredConformancesLinear(_: @differentiable(linear) (T) -> U) {} +inferredConformances(diffFunc) +inferredConformancesLinear(linearFunc) + +func inferredConformancesResult() -> @differentiable (T) -> U {} +func inferredConformancesResultLinear() -> @differentiable(linear) (T) -> U {} + +let diffFuncWithNondiff: @differentiable (Float, @noDerivative Int) -> Float +let linearFuncWithNondiff: @differentiable(linear) (Float, @noDerivative Int) -> Float +func inferredConformances(_: @differentiable (T, @noDerivative U) -> V) {} +func inferredConformancesLinear(_: @differentiable(linear) (T, @noDerivative U) -> V) {} +inferredConformances(diffFuncWithNondiff) +inferredConformancesLinear(linearFuncWithNondiff) + +struct Vector { + var x, y: T +} +extension Vector: Equatable where T: Equatable {} +extension Vector: AdditiveArithmetic where T: AdditiveArithmetic { + static var zero: Self { fatalError() } + static func + (lhs: Self, rhs: Self) -> Self { fatalError() } + static func - (lhs: Self, rhs: Self) -> Self { fatalError() } +} +extension Vector: Differentiable where T: Differentiable { + struct TangentVector: Equatable, AdditiveArithmetic, Differentiable { + var x, y: T.TangentVector + static var zero: Self { fatalError() } + static func + (lhs: Self, rhs: Self) -> Self { fatalError() } + static func - (lhs: Self, rhs: Self) -> Self { fatalError() } + typealias TangentVector = Self + } + mutating func move(along direction: TangentVector) { fatalError() } +} + +func inferredConformancesGeneric(_: @differentiable (Vector) -> Vector) {} + +// expected-error @+4 {{generic signature requires types 'Vector' and 'Vector.TangentVector' to be the same}} +// expected-error @+3 {{generic signature requires types 'Vector' and 'Vector.TangentVector' to be the same}} +// expected-error @+2 {{parameter type 'Vector' does not conform to 'Differentiable' and satisfy 'Vector == Vector.TangentVector', but the enclosing function type is '@differentiable(linear)'}} +// expected-error @+1 {{result type 'Vector' does not conform to 'Differentiable' and satisfy 'Vector == Vector.TangentVector', but the enclosing function type is '@differentiable(linear)'}} +func inferredConformancesGenericLinear(_: @differentiable(linear) (Vector) -> Vector) {} + +func nondiff(x: Vector) -> Vector {} +// expected-error @+1 {{global function 'inferredConformancesGeneric' requires that 'Int' conform to 'Differentiable}} +inferredConformancesGeneric(nondiff) +// expected-error @+1 {{global function 'inferredConformancesGenericLinear' requires that 'Int' conform to 'Differentiable}} +inferredConformancesGenericLinear(nondiff) + +func diff(x: Vector) -> Vector {} +inferredConformancesGeneric(diff) // okay! + +func inferredConformancesGenericResult() -> @differentiable (Vector) -> Vector {} +// expected-error @+4 {{generic signature requires types 'Vector' and 'Vector.TangentVector' to be the same}} +// expected-error @+3 {{generic signature requires types 'Vector' and 'Vector.TangentVector' to be the same}} +// expected-error @+2 {{parameter type 'Vector' does not conform to 'Differentiable' and satisfy 'Vector == Vector.TangentVector', but the enclosing function type is '@differentiable(linear)'}} +// expected-error @+1 {{result type 'Vector' does not conform to 'Differentiable' and satisfy 'Vector == Vector.TangentVector', but the enclosing function type is '@differentiable(linear)'}} +func inferredConformancesGenericResultLinear() -> @differentiable(linear) (Vector) -> Vector {} + +struct Linear { + var x, y: T +} +extension Linear: Equatable where T: Equatable {} +extension Linear: AdditiveArithmetic where T: AdditiveArithmetic {} +extension Linear: Differentiable where T: Differentiable, T == T.TangentVector { + typealias TangentVector = Self +} + +// expected-note @+1 2 {{where 'T' = 'Int'}} +func inferredConformancesGeneric(_: @differentiable (Linear) -> Linear) {} + +// expected-note @+1 2 {{where 'T' = 'Int'}} +func inferredConformancesGenericLinear(_: @differentiable(linear) (Linear) -> Linear) {} + +func nondiff(x: Linear) -> Linear {} +// expected-error @+1 {{global function 'inferredConformancesGeneric' requires that 'Int' conform to 'Differentiable}} +inferredConformancesGeneric(nondiff) +// expected-error @+1 {{global function 'inferredConformancesGenericLinear' requires that 'Int' conform to 'Differentiable}} +inferredConformancesGenericLinear(nondiff) + +func diff(x: Linear) -> Linear {} +inferredConformancesGeneric(diff) // okay! + +func inferredConformancesGenericResult() -> @differentiable (Linear) -> Linear {} +func inferredConformancesGenericResultLinear() -> @differentiable(linear) (Linear) -> Linear {} diff --git a/test/AutoDiff/Sema/missing_differentiable_protocol.swift b/test/AutoDiff/Sema/missing_differentiable_protocol.swift new file mode 100644 index 0000000000000..46752c7d1be38 --- /dev/null +++ b/test/AutoDiff/Sema/missing_differentiable_protocol.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend -enable-experimental-differentiable-programming -typecheck -verify %s + +// Tests that Sema fails gracefully when the `Differentiable` protocol is missing. + +// expected-error @+2 {{parameter type 'Float' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +// expected-error @+1 {{result type 'Float' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +let _: @differentiable (Float) -> Float + +// expected-error @+2 {{parameter type 'T' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +// expected-error @+1 {{result type 'T' does not conform to 'Differentiable', but the enclosing function type is '@differentiable'}} +func hasDifferentiableFunctionArg(_ f: @differentiable (T) -> T) {} diff --git a/test/AutoDiff/Serialization/differentiable_function.swift b/test/AutoDiff/Serialization/differentiable_function.swift index 7e1f8af5e6a67..3daf840cd78bb 100644 --- a/test/AutoDiff/Serialization/differentiable_function.swift +++ b/test/AutoDiff/Serialization/differentiable_function.swift @@ -5,6 +5,8 @@ // BCANALYZER-NOT: UnknownCode +import _Differentiation + func a(_ f: @differentiable (Float) -> Float) {} // CHECK: func a(_ f: @differentiable (Float) -> Float) diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index e3069a5297319..9c4283b69db7c 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -921,14 +921,6 @@ func test_trailing_closure_with_defaulted_last() { func foo(fn: () -> T, value: Int = 0) {} foo { 42 } // Ok foo(fn: { 42 }) // Ok - - func bar(type: T.Type, fn: T, a: Int = 0) {} - bar(type: (() -> Int).self) { 42 } - bar(type: (() -> Int).self, fn: { 42 }) - - func baz(fn: () -> Int, a: Int = 0, b: Int = 0, c: Int = 0) {} - baz { 42 } - baz(fn: { 42 }) } // Test that even in multi-statement closure case we still pick up `(Action) -> Void` over `Optional<(Action) -> Void>`. diff --git a/test/Index/Store/cross-import-overlay.swift b/test/Index/Store/cross-import-overlay.swift index 20c8c1c69a0c4..218186daa7c91 100644 --- a/test/Index/Store/cross-import-overlay.swift +++ b/test/Index/Store/cross-import-overlay.swift @@ -29,65 +29,65 @@ from__ABAdditionsCAdditions() // MAIN-NEXT: target: {{.*}} // MAIN-NEXT: is-debug: 1 // MAIN-NEXT: DEPEND START -// MAIN-NEXT: Unit | system | Swift | {{.*}}/Swift.swiftmodule -// MAIN-NEXT: Unit | system | B | {{.*}}/B.swiftmodule/{{.*}} -// MAIN-NEXT: Unit | system | C | {{.*}}/C.swiftmodule/{{.*}} -// MAIN-NEXT: Unit | system | A | {{.*}}/__ABAdditionsCAdditions.swiftmodule/{{.*}} -// MAIN-NEXT: Record | user | {{.*}}/cross-import-overlay.swift +// MAIN-NEXT: Unit | system | Swift | {{.*}}{{/|\\}}Swift.swiftmodule +// MAIN-NEXT: Unit | system | B | {{.*}}{{/|\\}}B.swiftmodule{{/|\\}}{{.*}} +// MAIN-NEXT: Unit | system | C | {{.*}}{{/|\\}}C.swiftmodule{{/|\\}}{{.*}} +// MAIN-NEXT: Unit | system | A | {{.*}}{{/|\\}}__ABAdditionsCAdditions.swiftmodule{{/|\\}}{{.*}} +// MAIN-NEXT: Record | user | {{.*}}{{/|\\}}cross-import-overlay.swift // MAIN-NEXT: DEPEND END // // RUN: %FileCheck %s --input-file %t/units --check-prefix=AB_OVERLAY // AB_OVERLAY: module-name: A -// AB_OVERLAY: out-file:{{.*}}/_ABAdditions.swiftmodule/{{.*}} +// AB_OVERLAY: out-file:{{.*}}{{/|\\}}_ABAdditions.swiftmodule{{/|\\}}{{.*}} // AB_OVERLAY-NEXT: target: {{.*}} // AB_OVERLAY-NEXT: is-debug: 1 // AB_OVERLAY-NEXT: DEPEND START -// AB_OVERLAY-NEXT: Unit | system | A | {{.*}}/A.swiftmodule/{{.*}} -// AB_OVERLAY-NEXT: Unit | system | B | {{.*}}/B.swiftmodule/{{.*}} -// AB_OVERLAY-NEXT: Unit | system | Swift | {{.*}}/Swift.swiftmodule -// AB_OVERLAY-NEXT: Record | system | A | {{.*}}/_ABAdditions.swiftmodule/{{.*}} +// AB_OVERLAY-NEXT: Unit | system | A | {{.*}}{{/|\\}}A.swiftmodule{{/|\\}}{{.*}} +// AB_OVERLAY-NEXT: Unit | system | B | {{.*}}{{/|\\}}B.swiftmodule{{/|\\}}{{.*}} +// AB_OVERLAY-NEXT: Unit | system | Swift | {{.*}}{{/|\\}}Swift.swiftmodule +// AB_OVERLAY-NEXT: Record | system | A | {{.*}}{{/|\\}}_ABAdditions.swiftmodule{{/|\\}}{{.*}} // AB_OVERLAY-NEXT: DEPEND END // // RUN: %FileCheck %s --input-file %t/units --check-prefix=ABC_OVERLAY // ABC_OVERLAY: module-name: A -// ABC_OVERLAY: out-file: {{.*}}/__ABAdditionsCAdditions.swiftmodule/{{.*}} +// ABC_OVERLAY: out-file: {{.*}}{{/|\\}}__ABAdditionsCAdditions.swiftmodule{{/|\\}}{{.*}} // ABC_OVERLAY-NEXT: target: {{.*}} // ABC_OVERLAY-NEXT: is-debug: 1 // ABC_OVERLAY-NEXT: DEPEND START -// ABC_OVERLAY-NEXT: Unit | system | C | {{.*}}/C.swiftmodule/{{.*}} -// ABC_OVERLAY-NEXT: Unit | system | Swift | {{.*}}/Swift.swiftmodule -// ABC_OVERLAY-NEXT: Unit | system | A | {{.*}}/_ABAdditions.swiftmodule/{{.*}} -// ABC_OVERLAY-NEXT: Record | system | A | {{.*}}/__ABAdditionsCAdditions.swiftmodule/{{.*}} +// ABC_OVERLAY-NEXT: Unit | system | C | {{.*}}{{/|\\}}C.swiftmodule{{/|\\}}{{.*}} +// ABC_OVERLAY-NEXT: Unit | system | Swift | {{.*}}{{/|\\}}Swift.swiftmodule +// ABC_OVERLAY-NEXT: Unit | system | A | {{.*}}{{/|\\}}_ABAdditions.swiftmodule{{/|\\}}{{.*}} +// ABC_OVERLAY-NEXT: Record | system | A | {{.*}}{{/|\\}}__ABAdditionsCAdditions.swiftmodule{{/|\\}}{{.*}} // ABC_OVERLAY-NEXT: DEPEND END // // RUN: %FileCheck %s --input-file %t/units --check-prefix=C_MODULE // C_MODULE: module-name: C -// C_MODULE: out-file: {{.*}}/C.swiftmodule/{{.*}} +// C_MODULE: out-file: {{.*}}{{/|\\}}C.swiftmodule{{/|\\}}{{.*}} // C_MODULE-NEXT: target: {{.*}} // C_MODULE-NEXT: is-debug: 1 // C_MODULE-NEXT: DEPEND START -// C_MODULE-NEXT: Unit | system | Swift | {{.*}}/Swift.swiftmodule -// C_MODULE-NEXT: Record | system | C | {{.*}}/C.swiftmodule/{{.*}} +// C_MODULE-NEXT: Unit | system | Swift | {{.*}}{{/|\\}}Swift.swiftmodule +// C_MODULE-NEXT: Record | system | C | {{.*}}{{/|\\}}C.swiftmodule{{/|\\}}{{.*}} // C_MODULE-NEXT: DEPEND END // // RUN: %FileCheck %s --input-file %t/units --check-prefix=B_MODULE // B_MODULE: module-name: B -// B_MODULE: out-file: {{.*}}/B.swiftmodule/{{.*}} +// B_MODULE: out-file: {{.*}}{{/|\\}}B.swiftmodule{{/|\\}}{{.*}} // B_MODULE-NEXT: target: {{.*}} // B_MODULE-NEXT: is-debug: 1 // B_MODULE-NEXT: DEPEND START -// B_MODULE-NEXT: Unit | system | Swift | {{.*}}/Swift.swiftmodule -// B_MODULE-NEXT: Record | system | B | {{.*}}/B.swiftmodule/{{.*}} +// B_MODULE-NEXT: Unit | system | Swift | {{.*}}{{/|\\}}Swift.swiftmodule +// B_MODULE-NEXT: Record | system | B | {{.*}}{{/|\\}}B.swiftmodule{{/|\\}}{{.*}} // B_MODULE-NEXT: DEPEND END // // RUN: %FileCheck %s --input-file %t/units --check-prefix=A_MODULE // A_MODULE: module-name: A -// A_MODULE: out-file: {{.*}}/A.swiftmodule/{{.*}} +// A_MODULE: out-file: {{.*}}{{/|\\}}A.swiftmodule{{/|\\}}{{.*}} // A_MODULE-NEXT: target: {{.*}} // A_MODULE-NEXT: is-debug: 1 // A_MODULE-NEXT: DEPEND START -// A_MODULE-NEXT: Unit | system | Swift | {{.*}}/Swift.swiftmodule -// A_MODULE-NEXT: Record | system | A | {{.*}}/A.swiftmodule/{{.*}} +// A_MODULE-NEXT: Unit | system | Swift | {{.*}}{{/|\\}}Swift.swiftmodule +// A_MODULE-NEXT: Record | system | A | {{.*}}{{/|\\}}A.swiftmodule{{/|\\}}{{.*}} // A_MODULE-NEXT: DEPEND END diff --git a/test/Index/index_cross_import.swift b/test/Index/index_cross_import.swift index b4dc7f683ebe8..f41c67d3acf57 100644 --- a/test/Index/index_cross_import.swift +++ b/test/Index/index_cross_import.swift @@ -11,21 +11,21 @@ // // CHECK: index_cross_import.swift // CHECK: ------------ -// CHECK-DAG: module | user | A | {{.*}}/A.swiftmodule/{{.*}} -// CHECK-DAG: module | user | A | {{.*}}/_ABAdditions.swiftmodule/{{.*}} -// CHECK-DAG: module | user | A | {{.*}}/__ABAdditionsCAdditions.swiftmodule/{{.*}} -// CHECK-DAG: module | user | B | {{.*}}/B.swiftmodule/{{.*}} -// CHECK-DAG: module | user | C | {{.*}}/C.swiftmodule/{{.*}} +// CHECK-DAG: module | user | A | {{.*}}{{/|\\}}A.swiftmodule{{/|\\}}{{.*}} +// CHECK-DAG: module | user | A | {{.*}}{{/|\\}}_ABAdditions.swiftmodule{{/|\\}}{{.*}} +// CHECK-DAG: module | user | A | {{.*}}{{/|\\}}__ABAdditionsCAdditions.swiftmodule{{/|\\}}{{.*}} +// CHECK-DAG: module | user | B | {{.*}}{{/|\\}}B.swiftmodule{{/|\\}}{{.*}} +// CHECK-DAG: module | user | C | {{.*}}{{/|\\}}C.swiftmodule{{/|\\}}{{.*}} // CHECK: ------------ import A -// CHECK: [[@LINE-1]]:8 | module/Swift | A | {{.*}} | Ref | rel: 0 +// CHECK: [[@LINE-1]]:8 | module{{/|\\}}Swift | A | {{.*}} | Ref | rel: 0 import B -// CHECK: [[@LINE-1]]:8 | module/Swift | B | {{.*}} | Ref | rel: 0 +// CHECK: [[@LINE-1]]:8 | module{{/|\\}}Swift | B | {{.*}} | Ref | rel: 0 import C -// CHECK: [[@LINE-1]]:8 | module/Swift | C | {{.*}} | Ref | rel: 0 +// CHECK: [[@LINE-1]]:8 | module{{/|\\}}Swift | C | {{.*}} | Ref | rel: 0 from_ABAdditions() -// CHECK: [[@LINE-1]]:1 | function/Swift | from_ABAdditions() | {{.*}} | Ref,Call | rel: 0 +// CHECK: [[@LINE-1]]:1 | function{{/|\\}}Swift | from_ABAdditions() | {{.*}} | Ref,Call | rel: 0 from__ABAdditionsCAdditions() -// CHECK: [[@LINE-1]]:1 | function/Swift | from__ABAdditionsCAdditions() | {{.*}} | Ref,Call | rel: 0 +// CHECK: [[@LINE-1]]:1 | function{{/|\\}}Swift | from__ABAdditionsCAdditions() | {{.*}} | Ref,Call | rel: 0 diff --git a/test/SILOptimizer/opt_enumerate.swift b/test/SILOptimizer/opt_enumerate.swift index f8720a76b334b..3d17f989d4899 100644 --- a/test/SILOptimizer/opt_enumerate.swift +++ b/test/SILOptimizer/opt_enumerate.swift @@ -24,3 +24,12 @@ public func eliminate_bounds_check(_ array: [Int]) { } } +// CHECK-LABEL: sil @$s4test27eliminate_two_bounds_checksyySaySiGF +// CHECK-NOT: cond_fail {{.*}} "Index out of range" +// CHECK: // end sil function '$s4test27eliminate_two_bounds_checksyySaySiGF' +public func eliminate_two_bounds_checks(_ array: [Int]) { + for (index, x) in array.enumerated() { + take(x, array[index]) + } +} + diff --git a/test/SILOptimizer/redundant_phi_elimination.sil b/test/SILOptimizer/redundant_phi_elimination.sil new file mode 100644 index 0000000000000..e6c645859f672 --- /dev/null +++ b/test/SILOptimizer/redundant_phi_elimination.sil @@ -0,0 +1,155 @@ +// RUN: %target-sil-opt -enable-sil-verify-all %s -redundant-phi-elimination | %FileCheck %s + +sil_stage canonical + +import Builtin +import Swift + +// CHECK-LABEL: sil @test_simple +// CHECK: bb1: +// CHECK: br bb3(%0 : $Builtin.Int64) +// CHECK: bb2: +// CHECK: br bb3(%1 : $Builtin.Int64) +// CHECK: bb3([[ARG:%[0-9]+]] : $Builtin.Int64): +// CHECK: builtin "sadd_with_overflow_Int64"([[ARG]] : $Builtin.Int64, [[ARG]] : $Builtin.Int64, +// CHECK: } // end sil function 'test_simple' +sil @test_simple : $@convention(thin) () -> () { +bb0: + %0 = integer_literal $Builtin.Int64, 0 + %1 = integer_literal $Builtin.Int64, 1 + %2 = integer_literal $Builtin.Int1, -1 + cond_br undef, bb1, bb2 + +bb1: + br bb3(%0 : $Builtin.Int64, %0 : $Builtin.Int64) + +bb2: + br bb3(%1 : $Builtin.Int64, %1 : $Builtin.Int64) + + +bb3(%4 : $Builtin.Int64, %5 : $Builtin.Int64): + %6 = builtin "sadd_with_overflow_Int64"(%4 : $Builtin.Int64, %5 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) + %8 = tuple_extract %6 : $(Builtin.Int64, Builtin.Int1), 1 + cond_fail %8 : $Builtin.Int1, "arithmetic overflow" + %r = tuple () + return %r : $() +} + +// CHECK-LABEL: sil @test_not_equal +// CHECK: bb1: +// CHECK: br bb3(%0 : $Builtin.Int64, %0 : $Builtin.Int64) +// CHECK: bb2: +// CHECK: br bb3(%0 : $Builtin.Int64, %1 : $Builtin.Int64) +// CHECK: bb3([[ARG1:%[0-9]+]] : $Builtin.Int64, [[ARG2:%[0-9]+]] : $Builtin.Int64): +// CHECK: builtin "sadd_with_overflow_Int64"([[ARG1]] : $Builtin.Int64, [[ARG2]] : $Builtin.Int64, +// CHECK: } // end sil function 'test_not_equal' +sil @test_not_equal : $@convention(thin) () -> () { +bb0: + %0 = integer_literal $Builtin.Int64, 0 + %1 = integer_literal $Builtin.Int64, 1 + %2 = integer_literal $Builtin.Int1, -1 + cond_br undef, bb1, bb2 + +bb1: + br bb3(%0 : $Builtin.Int64, %0 : $Builtin.Int64) + +bb2: + br bb3(%0 : $Builtin.Int64, %1 : $Builtin.Int64) + + +bb3(%4 : $Builtin.Int64, %5 : $Builtin.Int64): + %6 = builtin "sadd_with_overflow_Int64"(%4 : $Builtin.Int64, %5 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) + %8 = tuple_extract %6 : $(Builtin.Int64, Builtin.Int1), 1 + cond_fail %8 : $Builtin.Int1, "arithmetic overflow" + %r = tuple () + return %r : $() +} + +sil @unknown : $@convention(thin) () -> Builtin.Int64 + +// CHECK-LABEL: sil @test_side_effects +// CHECK: [[A1:%[0-9]+]] = apply +// CHECK: [[A2:%[0-9]+]] = apply +// CHECK: br bb1([[A1]] : $Builtin.Int64, [[A2]] : $Builtin.Int64) +// CHECK: bb1([[ARG1:%[0-9]+]] : $Builtin.Int64, [[ARG2:%[0-9]+]] : $Builtin.Int64): +// CHECK: builtin "sadd_with_overflow_Int64"([[ARG1]] : $Builtin.Int64, [[ARG2]] : $Builtin.Int64, +// CHECK: } // end sil function 'test_side_effects' +sil @test_side_effects : $@convention(thin) () -> () { +bb0: + %f = function_ref @unknown : $@convention(thin) () -> Builtin.Int64 + %0 = apply %f() : $@convention(thin) () -> Builtin.Int64 + %1 = apply %f() : $@convention(thin) () -> Builtin.Int64 + %2 = integer_literal $Builtin.Int1, -1 + br bb1(%0 : $Builtin.Int64, %1 : $Builtin.Int64) + +bb1(%4 : $Builtin.Int64, %5 : $Builtin.Int64): + %6 = builtin "sadd_with_overflow_Int64"(%4 : $Builtin.Int64, %5 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) + %8 = tuple_extract %6 : $(Builtin.Int64, Builtin.Int1), 1 + cond_fail %8 : $Builtin.Int1, "arithmetic overflow" + %r = tuple () + return %r : $() +} + +// CHECK-LABEL: sil @test_loop +// CHECK: br bb1(%0 : $Builtin.Int64) +// CHECK: bb1([[ARG:%[0-9]+]] : $Builtin.Int64): +// CHECK: [[S1:%[0-9]+]] = builtin "sadd_with_overflow_Int64"([[ARG]] : $Builtin.Int64, +// CHECK: [[T1:%[0-9]+]] = tuple_extract [[S1]] {{.*}}, 0 +// CHECK: [[T2:%[0-9]+]] = tuple_extract [[S1]] {{.*}}, 1 +// CHECK: cond_fail [[T2]] +// CHECK: [[S2:%[0-9]+]] = builtin "sadd_with_overflow_Int64"([[ARG]] : $Builtin.Int64, +// CHECK: [[T3:%[0-9]+]] = tuple_extract [[S2]] {{.*}}, 1 +// CHECK: cond_fail [[T3]] +// CHECK: bb2: +// CHECK: br bb1([[T1]] : $Builtin.Int64) +// CHECK: } // end sil function 'test_loop' +sil @test_loop : $@convention(thin) () -> () { +bb0: + %0 = integer_literal $Builtin.Int64, 0 + %1 = integer_literal $Builtin.Int64, 1 + %2 = integer_literal $Builtin.Int1, -1 + br bb1(%0 : $Builtin.Int64, %0 : $Builtin.Int64) + + +bb1(%4 : $Builtin.Int64, %5 : $Builtin.Int64): + %6 = builtin "sadd_with_overflow_Int64"(%4 : $Builtin.Int64, %1 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) + %7 = tuple_extract %6 : $(Builtin.Int64, Builtin.Int1), 0 + %8 = tuple_extract %6 : $(Builtin.Int64, Builtin.Int1), 1 + cond_fail %8 : $Builtin.Int1, "arithmetic overflow" + %10 = builtin "sadd_with_overflow_Int64"(%5 : $Builtin.Int64, %1 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) + %11 = tuple_extract %10 : $(Builtin.Int64, Builtin.Int1), 0 + %12 = tuple_extract %10 : $(Builtin.Int64, Builtin.Int1), 1 + cond_fail %12 : $Builtin.Int1, "arithmetic overflow" + cond_br undef, bb2, bb3 + +bb2: + br bb1(%7 : $Builtin.Int64, %11 : $Builtin.Int64) + +bb3: + %r = tuple () + return %r : $() +} + +// CHECK-LABEL: sil @test_mismatching_arg +// CHECK: br bb1(%0 : $Builtin.Int64, %0 : $Builtin.Int64) +// CHECK: bb1([[ARG1:%[0-9]+]] : $Builtin.Int64, {{%[0-9]+}} : $Builtin.Int64): +// CHECK: bb2: +// CHECK: br bb1([[ARG1]] : $Builtin.Int64, %1 : $Builtin.Int64) +// CHECK: } // end sil function 'test_mismatching_arg' +sil @test_mismatching_arg : $@convention(thin) () -> () { +bb0: + %0 = integer_literal $Builtin.Int64, 0 + %1 = integer_literal $Builtin.Int64, 1 + br bb1(%0 : $Builtin.Int64, %0 : $Builtin.Int64) + + +bb1(%4 : $Builtin.Int64, %5 : $Builtin.Int64): + cond_br undef, bb2, bb3 + +bb2: + br bb1(%4 : $Builtin.Int64, %1 : $Builtin.Int64) + +bb3: + %r = tuple () + return %r : $() +} diff --git a/test/TBD/implied_objc_symbols.swift b/test/TBD/implied_objc_symbols.swift deleted file mode 100644 index abe8e6eb08b06..0000000000000 --- a/test/TBD/implied_objc_symbols.swift +++ /dev/null @@ -1,12 +0,0 @@ -// REQUIRES: VENDOR=apple -// RUN: %empty-directory(%t) - -// RUN: echo "import Foundation" > %t/main.swift -// RUN: echo "@objc public class ObjCOnly {}" >> %t/main.swift -// RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -import-objc-header %S/Inputs/objc_class_header.h -validate-tbd-against-ir=missing %t/main.swift -disable-objc-attr-requires-foundation-module -emit-tbd -emit-tbd-path %t/main.tbd - -// RUN: %FileCheck %s < %t/main.tbd - -// CHECK: __TtC4test8ObjCOnly -// CHECK-NOT: _OBJC_CLASS_ -// CHECK-NOT: _OBJC_METACLASS_ diff --git a/test/swift-indent/basic.swift b/test/swift-indent/basic.swift index 1384e34c4308b..940fedf21be65 100644 --- a/test/swift-indent/basic.swift +++ b/test/swift-indent/basic.swift @@ -326,6 +326,15 @@ var array: [String] = { "two"] }() #endif +#if os(iOS) +var source: String? { + if true { + if otherCondition { + return "true" + } + } +} +#endif // Comments should not affect switch case indentations. diff --git a/validation-test/stdlib/XCTest.swift b/validation-test/stdlib/XCTest.swift index 62c491228ec4c..17a4bde588d22 100644 --- a/validation-test/stdlib/XCTest.swift +++ b/validation-test/stdlib/XCTest.swift @@ -1,7 +1,20 @@ // RUN: rm -rf %t ; mkdir -p %t -// RUN: %target-build-swift %s -o %t/a.out -swift-version 4 && %target-run %t/a.out +// RUN: %target-build-swift %s -o %t/a.out -swift-version 4 + +// The actual XCTest overlay is not maintained in this repository -- it is +// distributed in Xcode (libXCTestSwiftSupport.dylib), along with +// XCTest.framework itself. +// +// The codebase here builds the obsolete /usr/lib/swift/libswiftXCTest.dylib +// that currently ships in the OS. There is no expectation that that library is +// usable for anything; it only exists to maintain a superficial level of binary +// compatibility with existing apps that happen to link to it by mistake. +// +// Accordingly, this test is now a build-only test. The code here is only +// compiled, it is never run. +// +// rdar://problem/55270944 -// REQUIRES: executable_test // REQUIRES: objc_interop // FIXME: Add a feature for "platforms that support XCTest".