diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index 103b382e9ba50..5c1eaa91fe286 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -57,6 +57,7 @@ SWIFT_TYPEID_NAMED(PatternBindingEntry *, PatternBindingEntry) SWIFT_TYPEID_NAMED(PostfixOperatorDecl *, PostfixOperatorDecl) SWIFT_TYPEID_NAMED(PrecedenceGroupDecl *, PrecedenceGroupDecl) SWIFT_TYPEID_NAMED(PrefixOperatorDecl *, PrefixOperatorDecl) +SWIFT_TYPEID_NAMED(ProtocolConformance *, ProtocolConformance) SWIFT_TYPEID_NAMED(ProtocolDecl *, ProtocolDecl) SWIFT_TYPEID_NAMED(SourceFile *, SourceFile) SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl) diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h index c4bebdfade92b..9359f95427d0e 100644 --- a/include/swift/AST/ASTTypeIDs.h +++ b/include/swift/AST/ASTTypeIDs.h @@ -52,6 +52,7 @@ struct PropertyWrapperTypeInfo; enum class CtorInitializerKind; struct PropertyWrapperLValueness; struct PropertyWrapperMutability; +class ProtocolConformance; class ProtocolDecl; class Requirement; enum class ResilienceExpansion : unsigned; diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index f96cb3b00edad..e8581d3cbc515 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -5069,6 +5069,14 @@ NOTE(function_builder_remove_attr, none, "remove the attribute to explicitly disable the function builder", ()) NOTE(function_builder_remove_returns, none, "remove 'return' statements to apply the function builder", ()) +ERROR(function_builder_infer_ambig, none, + "ambiguous function builder inferred for %0: %1 or %2", + (DeclName, Type, Type)) +NOTE(function_builder_infer_add_return, none, + "add an explicit 'return' statement to not use a function builder", ()) +NOTE(function_builder_infer_pick_specific, none, + "apply function builder %0 (inferred from protocol %1)", + (Type, DeclName)) //------------------------------------------------------------------------------ // MARK: Tuple Shuffle Diagnostics diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 2d8f1bb7f7257..8fffe1e39a6ba 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -2240,7 +2240,7 @@ class ClosureHasExplicitResultRequest bool isCached() const { return true; } }; -using ProtocolConformanceLookupResult = SmallVector; +using ProtocolConformanceLookupResult = std::vector; void simple_display(llvm::raw_ostream &out, ConformanceLookupKind kind); /// Lookup and expand all conformances in the given context. @@ -2262,7 +2262,7 @@ class LookupAllConformancesInContextRequest : public SimpleRequest { public: @@ -2276,6 +2276,8 @@ class LookupAllConformancesInContextRequest evaluate(Evaluator &evaluator, const IterableDeclContext *IDC) const; public: + bool isCached() const { return true; } + // Incremental dependencies evaluator::DependencySource readDependencySource(const evaluator::DependencyRecorder &eval) const; diff --git a/include/swift/Basic/SimpleDisplay.h b/include/swift/Basic/SimpleDisplay.h index 3a553359091aa..3a31da14654ac 100644 --- a/include/swift/Basic/SimpleDisplay.h +++ b/include/swift/Basic/SimpleDisplay.h @@ -136,6 +136,20 @@ namespace swift { out << "}"; } + template + void simple_display(llvm::raw_ostream &out, + const std::vector &vec) { + out << "{"; + bool first = true; + for (const T &value : vec) { + if (first) first = false; + else out << ", "; + + simple_display(out, value); + } + out << "}"; + } + template void simple_display(llvm::raw_ostream &out, const llvm::PointerUnion &ptrUnion) { diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 2b339f12fb75a..cf90377151b74 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -758,11 +758,13 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, case DAK_Custom: { if (!Options.IsForSwiftInterface) break; - // For Swift interface, we should only print function builder attribute - // on parameter decls. Printing the attribute elsewhere isn't ABI relevant. + // For Swift interface, we should print function builder attributes + // on parameter decls and on protocol requirements. + // Printing the attribute elsewhere isn't ABI relevant. if (auto *VD = dyn_cast(D)) { if (VD->getAttachedFunctionBuilder() == this) { - if (!isa(D)) + if (!isa(D) && + !(isa(D) && isa(D->getDeclContext()))) return false; } } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 6e4be31422f3f..13a4d46dcac9e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6324,10 +6324,6 @@ void ParamDecl::setStoredProperty(VarDecl *var) { } Type ValueDecl::getFunctionBuilderType() const { - // Fast path: most declarations (especially parameters, which is where - // this is hottest) do not have any custom attributes at all. - if (!getAttrs().hasAttribute()) return Type(); - auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, @@ -6336,10 +6332,6 @@ Type ValueDecl::getFunctionBuilderType() const { } CustomAttr *ValueDecl::getAttachedFunctionBuilder() const { - // Fast path: most declarations (especially parameters, which is where - // this is hottest) do not have any custom attributes at all. - if (!getAttrs().hasAttribute()) return nullptr; - auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index b2265af0885f2..b5b4b88c4c266 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1401,10 +1401,6 @@ BraceStmt *swift::applyFunctionBuilderTransform( captured.first, captured.second))); } -/// Find the return statements in the given body, which block the application -/// of a function builder. -static std::vector findReturnStatements(AnyFunctionRef fn); - Optional TypeChecker::applyFunctionBuilderBodyTransform( FuncDecl *func, Type builderType) { // Pre-check the body: pre-check any expressions in it and look @@ -1708,7 +1704,7 @@ PreCheckFunctionBuilderRequest::evaluate(Evaluator &eval, return PreCheckFunctionBuilderApplication(fn, false).run(); } -std::vector findReturnStatements(AnyFunctionRef fn) { +std::vector TypeChecker::findReturnStatements(AnyFunctionRef fn) { PreCheckFunctionBuilderApplication precheck(fn, true); (void)precheck.run(); return precheck.getReturnStmts(); diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 55438f3440153..7e68315383a1f 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -287,9 +287,11 @@ getStructuralTypeContext(const Solution &solution, ConstraintLocator *locator) { solution.getType(coerceExpr->getSubExpr()), solution.getType(coerceExpr)); } else if (auto *assignExpr = getAsExpr(locator->getAnchor())) { - return std::make_tuple(CTP_AssignSource, + auto CTP = isa(assignExpr->getDest()) ? CTP_SubscriptAssignSource + : CTP_AssignSource; + return std::make_tuple(CTP, solution.getType(assignExpr->getSrc()), - solution.getType(assignExpr->getDest())); + solution.getType(assignExpr->getDest())->getRValueType()); } else if (auto *call = getAsExpr(locator->getAnchor())) { assert(isa(call->getFn())); return std::make_tuple( @@ -332,8 +334,10 @@ bool AllowTupleTypeMismatch::coalesceAndDiagnose( return false; } - TupleContextualFailure failure(solution, purpose, fromType, toType, indices, - locator); + TupleContextualFailure failure(solution, purpose, + fromType->lookThroughAllOptionalTypes(), + toType->lookThroughAllOptionalTypes(), + indices, locator); return failure.diagnose(asNote); } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index b8b54d33893c5..4fd66d5a5cbf3 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -3356,13 +3356,18 @@ bool ConstraintSystem::repairFailures( // related to immutability, otherwise it's a type mismatch. auto result = matchTypes(lhs, rhs, ConstraintKind::Conversion, TMF_ApplyingFix, locator); - + + auto *loc = getConstraintLocator(locator); if (getType(destExpr)->is() || result.isFailure()) { - conversionsOrFixes.push_back(IgnoreAssignmentDestinationType::create( - *this, lhs, rhs, getConstraintLocator(locator))); - } else { + // Let this asignment failure be diagnosed by the AllowTupleTypeMismatch + // fix already recorded. + if (hasFixFor(loc, FixKind::AllowTupleTypeMismatch)) + return true; + conversionsOrFixes.push_back( - TreatRValueAsLValue::create(*this, getConstraintLocator(locator))); + IgnoreAssignmentDestinationType::create(*this, lhs, rhs, loc)); + } else { + conversionsOrFixes.push_back(TreatRValueAsLValue::create(*this, loc)); } return true; @@ -8865,6 +8870,11 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( CoerceToCheckedCast::attempt(*this, fromType, toType, loc)) return !recordFix(fix, impact); } + + // We already have a fix for this locator indicating a + // tuple mismatch. + if (hasFixFor(loc, FixKind::AllowTupleTypeMismatch)) + return true; if (restriction == ConversionRestrictionKind::ValueToOptional || restriction == ConversionRestrictionKind::OptionalToOptional) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index eb2d702d3407b..11638181661cf 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2971,9 +2971,11 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { // Module interfaces don't print bodies for all getters, so allow getters // that don't have a body if we're compiling a module interface. + // Within a protocol definition, there will never be a body. SourceFile *parent = storage->getDeclContext()->getParentSourceFile(); bool isInInterface = parent && parent->Kind == SourceFileKind::Interface; - if (!isInInterface && !getter->hasBody()) + if (!isInInterface && !getter->hasBody() && + !isa(storage->getDeclContext())) return true; return false; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index b0c09e87d9d8b..de0c2a454d382 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -5037,10 +5037,11 @@ diagnoseMissingAppendInterpolationMethod(NominalTypeDecl *typeDecl) { } } -SmallVector +std::vector LookupAllConformancesInContextRequest::evaluate( Evaluator &eval, const IterableDeclContext *IDC) const { - return IDC->getLocalConformances(ConformanceLookupKind::All); + auto result = IDC->getLocalConformances(ConformanceLookupKind::All); + return std::vector(result.begin(), result.end()); } void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) { diff --git a/lib/Sema/TypeCheckRequestFunctions.cpp b/lib/Sema/TypeCheckRequestFunctions.cpp index fd789fc4df40d..bf26315290381 100644 --- a/lib/Sema/TypeCheckRequestFunctions.cpp +++ b/lib/Sema/TypeCheckRequestFunctions.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/NameLookupRequests.h" +#include "swift/AST/ProtocolConformance.h" #include "swift/AST/TypeLoc.h" #include "swift/AST/Types.h" #include "swift/Subsystems.h" @@ -182,11 +183,115 @@ AttachedFunctionBuilderRequest::evaluate(Evaluator &evaluator, return nullptr; } +/// Attempt to infer the function builder type for a declaration. +static Type inferFunctionBuilderType(ValueDecl *decl) { + auto dc = decl->getDeclContext(); + if (!dc->isTypeContext() || isa(dc)) + return Type(); + + auto funcDecl = dyn_cast(decl); + if (!funcDecl || !funcDecl->hasBody() || + !decl->getDeclContext()->getParentSourceFile()) + return Type(); + + // Check whether there are any return statements in the function's body. + // If there are, the function builder transform will be disabled, + // so don't infer a function builder. + if (!TypeChecker::findReturnStatements(funcDecl).empty()) + return Type(); + + // Only getters can have function builders. When we find one, look at + // the storage declaration for the purposes of witness matching. + auto lookupDecl = decl; + if (auto accessor = dyn_cast(funcDecl)) { + if (accessor->getAccessorKind() != AccessorKind::Get) + return Type(); + + lookupDecl = accessor->getStorage(); + } + + // Determine all of the conformances within the same context as + // this declaration. If this declaration is a witness to any + // requirement within one of those protocols that has a function builder + // attached, use that function builder type. + auto idc = cast(dc->getAsDecl()); + auto conformances = evaluateOrDefault( + dc->getASTContext().evaluator, + LookupAllConformancesInContextRequest{idc}, { }); + + // Find all of the potentially inferred function builder types. + struct Match { + ProtocolConformance *conformance; + ValueDecl *requirement; + Type functionBuilderType; + }; + SmallVector matches; + for (auto conformance : conformances) { + auto protocol = conformance->getProtocol(); + for (auto found : protocol->lookupDirect(lookupDecl->getName())) { + if (!isa(found->getDeclContext())) + continue; + + auto requirement = dyn_cast(found); + if (!requirement) + continue; + + Type functionBuilderType = requirement->getFunctionBuilderType(); + if (!functionBuilderType) + continue; + + auto witness = conformance->getWitnessDecl(requirement); + if (witness != lookupDecl) + continue; + + // Substitute into the function builder type. + auto subs = conformance->getSubstitutions(decl->getModuleContext()); + Type subFunctionBuilderType = functionBuilderType.subst(subs); + + matches.push_back({conformance, requirement, subFunctionBuilderType}); + } + } + + if (matches.size() == 0) + return Type(); + + // Determine whether there is more than one actual function builder type. + Type functionBuilderType = matches[0].functionBuilderType; + for (const auto &match : matches) { + // If the types were the same anyway, there's nothing to do. + Type otherFunctionBuilderType = match.functionBuilderType; + if (functionBuilderType->isEqual(otherFunctionBuilderType)) + continue; + + // We have at least two different function builder types. + // Diagnose the ambiguity and provide potential solutions. + decl->diagnose( + diag::function_builder_infer_ambig, lookupDecl->getName(), + functionBuilderType, otherFunctionBuilderType); + decl->diagnose(diag::function_builder_infer_add_return) + .fixItInsert(funcDecl->getBodySourceRange().End, "return <#expr#>\n"); + for (const auto &match : matches) { + decl->diagnose( + diag::function_builder_infer_pick_specific, + match.functionBuilderType, + match.conformance->getProtocol()->getName()) + .fixItInsert( + lookupDecl->getAttributeInsertionLoc(false), + "@" + match.functionBuilderType.getString() + " "); + } + + return Type(); + } + + return functionBuilderType; +} + Type FunctionBuilderTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { // Look for a function-builder custom attribute. auto attr = decl->getAttachedFunctionBuilder(); - if (!attr) return Type(); + if (!attr) + return inferFunctionBuilderType(decl); // Resolve a type for the attribute. auto mutableAttr = const_cast(attr); diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index a94e8c35edefc..2a0f34f76ef6e 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1862,7 +1862,8 @@ TypeCheckFunctionBodyUntilRequest::evaluate(Evaluator &evaluator, if (auto *func = dyn_cast(AFD)) { if (Type builderType = getFunctionBuilderType(func)) { if (auto optBody = - TypeChecker::applyFunctionBuilderBodyTransform(func, builderType)) { + TypeChecker::applyFunctionBuilderBodyTransform( + func, builderType)) { if (!*optBody) return true; diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 588ac6d1254b2..ab1e52a13eeb6 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -561,6 +561,9 @@ bool typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD); Optional applyFunctionBuilderBodyTransform(FuncDecl *func, Type builderType); +/// Find the return statements within the body of the given function. +std::vector findReturnStatements(AnyFunctionRef fn); + bool typeCheckClosureBody(ClosureExpr *closure); bool typeCheckTapBody(TapExpr *expr, DeclContext *DC); diff --git a/lib/SymbolGraphGen/SymbolGraph.cpp b/lib/SymbolGraphGen/SymbolGraph.cpp index fb60ff321df7c..29ade8e54f166 100644 --- a/lib/SymbolGraphGen/SymbolGraph.cpp +++ b/lib/SymbolGraphGen/SymbolGraph.cpp @@ -48,9 +48,9 @@ PrintOptions SymbolGraph::getDeclarationFragmentsPrintOptions() const { Opts.FunctionDefinitions = false; Opts.ArgAndParamPrinting = PrintOptions::ArgAndParamPrintingMode::MatchSource; - Opts.PrintGetSetOnRWProperties = false; - Opts.PrintPropertyAccessors = false; - Opts.PrintSubscriptAccessors = false; + Opts.PrintGetSetOnRWProperties = true; + Opts.PrintPropertyAccessors = true; + Opts.PrintSubscriptAccessors = true; Opts.SkipUnderscoredKeywords = true; Opts.SkipAttributes = true; Opts.PrintOverrideKeyword = true; @@ -76,6 +76,16 @@ SymbolGraph::getSubHeadingDeclarationFragmentsPrintOptions() const { auto Options = getDeclarationFragmentsPrintOptions(); Options.ArgAndParamPrinting = PrintOptions::ArgAndParamPrintingMode::ArgumentOnly; + + //--------------------------------------------------------------------------// + // Although we want these in the full declaration presentation, + // particularly for protocol requirements, + // we don't want to show these in subheadings. + Options.PrintGetSetOnRWProperties = false; + Options.PrintPropertyAccessors = false; + Options.PrintSubscriptAccessors = false; + //--------------------------------------------------------------------------// + Options.VarInitializers = false; Options.PrintDefaultArgumentValue = false; Options.PrintEmptyArgumentNames = false; diff --git a/test/Constraints/function_builder_infer.swift b/test/Constraints/function_builder_infer.swift new file mode 100644 index 0000000000000..7444cbb179110 --- /dev/null +++ b/test/Constraints/function_builder_infer.swift @@ -0,0 +1,186 @@ +// RUN: %target-typecheck-verify-swift -disable-availability-checking + +enum Either { + case first(T) + case second(U) +} + +@_functionBuilder +struct TupleBuilder { + static func buildBlock() -> () { + return () + } + + static func buildBlock(_ t1: T1) -> (T1) { + return (t1) + } + + static func buildBlock(_ t1: T1, _ t2: T2) -> (T1, T2) { + return (t1, t2) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3) + -> (T1, T2, T3) { + return (t1, t2, t3) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4) + -> (T1, T2, T3, T4) { + return (t1, t2, t3, t4) + } + + static func buildBlock( + _ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5 + ) -> (T1, T2, T3, T4, T5) { + return (t1, t2, t3, t4, t5) + } + + static func buildDo(_ value: T) -> T { return value } + static func buildIf(_ value: T?) -> T? { return value } + + static func buildEither(first value: T) -> Either { + return .first(value) + } + static func buildEither(second value: U) -> Either { + return .second(value) + } +} + +protocol Tupled { + associatedtype TupleType + + @TupleBuilder var tuple: TupleType { get } +} + +struct TupleMe: Tupled { + var condition: Bool + + // Okay: applies the function builder @TupleBuilder. + var tuple: some Any { + "hello" + if condition { + "nested" + } + 3.14159 + "world" + } +} + +// Witness is separated from the context declaring conformance, so don't infer +// the function builder. +struct DoNotTupleMe { + var condition: Bool + + var tuple: some Any { // expected-error{{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}} + "hello" // expected-warning{{string literal is unused}} + "world" // expected-warning{{string literal is unused}} + } +} + +extension DoNotTupleMe: Tupled { } + +@_functionBuilder +struct OtherTupleBuilder { + static func buildBlock() -> () { + return () + } + + static func buildBlock(_ t1: T1) -> (T1) { + return (t1) + } + + static func buildBlock(_ t1: T1, _ t2: T2) -> (T1, T2) { + return (t1, t2) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3) + -> (T1, T2, T3) { + return (t1, t2, t3) + } + + static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4) + -> (T1, T2, T3, T4) { + return (t1, t2, t3, t4) + } + + static func buildBlock( + _ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5 + ) -> (T1, T2, T3, T4, T5) { + return (t1, t2, t3, t4, t5) + } + + static func buildDo(_ value: T) -> T { return value } + static func buildIf(_ value: T?) -> T? { return value } + + static func buildEither(first value: T) -> Either { + return .first(value) + } + static func buildEither(second value: U) -> Either { + return .second(value) + } +} + +protocol Tupled2 { + associatedtype TupleType + + @TupleBuilder var tuple: TupleType { get } +} + +struct TupleMe2: Tupled, Tupled2 { + var condition: Bool + + // Okay: applies the function builder @TupleBuilder, even though it satisfies + // two requirements. (They have the same function builder) + var tuple: some Any { + "hello" + if condition { + "nested" + } + 3.14159 + "world" + } +} + +protocol OtherTupled { + associatedtype OtherTupleType + + @OtherTupleBuilder var tuple: OtherTupleType { get } +} + +struct AmbigTupleMe: Tupled, OtherTupled { + var condition: Bool + + // Ambiguous + internal + var tuple: Void { // expected-error{{ambiguous function builder inferred for 'tuple': 'TupleBuilder' or 'OtherTupleBuilder'}} + // expected-note@-1{{add an explicit 'return' statement to not use a function builder}}{{3-3=return <#expr#>\n}} + // expected-note@-2{{apply function builder 'TupleBuilder' (inferred from protocol 'Tupled')}}{{3-3=@TupleBuilder }} + // expected-note@-3{{apply function builder 'OtherTupleBuilder' (inferred from protocol 'OtherTupled')}}{{3-3=@OtherTupleBuilder }} + "hello" // expected-warning{{string literal is unused}} + "world" // expected-warning{{string literal is unused}} + } +} + +// Separating the conformances resolves the ambiguity. +struct TupleMeResolvedSeparate: Tupled { + var condition: Bool + + var tuple: some Any { + "hello" + if condition { + "nested" + } + 3.14159 + "world" + } +} + +extension TupleMeResolvedSeparate: OtherTupled { } + +struct TupleMeResolvedExplicit: Tupled, OtherTupled { + var condition: Bool + + var tuple: some Any { + return "hello" + } +} diff --git a/test/Constraints/tuple.swift b/test/Constraints/tuple.swift index ced92529e35ec..c452ea7b2b335 100644 --- a/test/Constraints/tuple.swift +++ b/test/Constraints/tuple.swift @@ -318,3 +318,20 @@ struct DupLabelSubscript { let dupLabelSubscriptStruct = DupLabelSubscript() let _ = dupLabelSubscriptStruct[foo: 5, foo: 5] // ok + +// SR-12869 + +var dict: [String: (Int, Int)] = [:] +let bignum: Int64 = 1337 +dict["test"] = (bignum, 1) // expected-error {{cannot assign value of type '(Int64, Int)' to subscript of type '(Int, Int)'}} + +var tuple: (Int, Int) +tuple = (bignum, 1) // expected-error {{cannot assign value of type '(Int64, Int)' to type '(Int, Int)'}} + +var optionalTuple: (Int, Int)? +var optionalTuple2: (Int64, Int)? = (bignum, 1) +var optionalTuple3: (UInt64, Int)? = (bignum, 1) // expected-error {{cannot convert value of type '(Int64, Int)' to specified type '(UInt64, Int)?'}} + +optionalTuple = (bignum, 1) // expected-error {{cannot assign value of type '(Int64, Int)' to type '(Int, Int)'}} +// Optional to Optional +optionalTuple = optionalTuple2 // expected-error {{cannot assign value of type '(Int64, Int)?' to type '(Int, Int)?'}} diff --git a/test/Incremental/Verifier/single-file-private/AnyObject.swift b/test/Incremental/Verifier/single-file-private/AnyObject.swift index 63aaaac49d028..6f04c986b52d3 100644 --- a/test/Incremental/Verifier/single-file-private/AnyObject.swift +++ b/test/Incremental/Verifier/single-file-private/AnyObject.swift @@ -65,3 +65,11 @@ func lookupOnAnyObject(object: AnyObject) { // expected-provides {{lookupOnAnyOb _ = object.someMember // expected-private-dynamic-member {{someMember}} object.someMethod() // expected-private-dynamic-member {{someMethod}} } + +// expected-private-member {{Swift.Hashable.someMethod}} +// expected-private-member {{Foundation._KeyValueCodingAndObserving.someMethod}} +// expected-private-member {{Foundation._KeyValueCodingAndObservingPublishing.someMethod}} +// expected-private-member {{Swift.Equatable.someMethod}} +// expected-private-member {{Swift.CVarArg.someMethod}} +// expected-private-member {{Swift.CustomStringConvertible.someMethod}} +// expected-private-member {{Swift.CustomDebugStringConvertible.someMethod}} diff --git a/test/Incremental/Verifier/single-file/AnyObject.swift b/test/Incremental/Verifier/single-file/AnyObject.swift index cc7cd837a0828..b5c17f3a27fd7 100644 --- a/test/Incremental/Verifier/single-file/AnyObject.swift +++ b/test/Incremental/Verifier/single-file/AnyObject.swift @@ -65,3 +65,10 @@ func lookupOnAnyObject(object: AnyObject) { // expected-provides {{lookupOnAnyOb _ = object.someMember // expected-private-dynamic-member {{someMember}} object.someMethod() // expected-private-dynamic-member {{someMethod}} } +// expected-private-member {{Swift.Hashable.someMethod}} +// expected-private-member {{Foundation._KeyValueCodingAndObserving.someMethod}} +// expected-private-member {{Foundation._KeyValueCodingAndObservingPublishing.someMethod}} +// expected-private-member {{Swift.Equatable.someMethod}} +// expected-private-member {{Swift.CVarArg.someMethod}} +// expected-private-member {{Swift.CustomStringConvertible.someMethod}} +// expected-private-member {{Swift.CustomDebugStringConvertible.someMethod}} diff --git a/test/ModuleInterface/function_builders.swift b/test/ModuleInterface/function_builders.swift index 1dc7d3e7d40dc..e471241774eda 100644 --- a/test/ModuleInterface/function_builders.swift +++ b/test/ModuleInterface/function_builders.swift @@ -47,3 +47,10 @@ public struct UsesBuilderProperty { // CHECK: public func myFunc(@FunctionBuilders.TupleBuilder fn: () -> ()) public func myFunc(@TupleBuilder fn: () -> ()) {} } + +public protocol ProtocolWithBuilderProperty { + associatedtype Assoc + + // CHECK: @FunctionBuilders.TupleBuilder var myVar: Self.Assoc { get } + @TupleBuilder var myVar: Assoc { get } +} diff --git a/test/Serialization/function_builders.swift b/test/Serialization/function_builders.swift new file mode 100644 index 0000000000000..1f866ff7538e0 --- /dev/null +++ b/test/Serialization/function_builders.swift @@ -0,0 +1,36 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -o %t %s +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -print-module -skip-deinit=false -module-to-print=function_builders -I %t -source-filename=%s | %FileCheck %s + +@_functionBuilder +public struct TupleBuilder { + public static func buildBlock(_ t1: T1, _ t2: T2) -> (T1, T2) { + return (t1, t2) + } + + public static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3) + -> (T1, T2, T3) { + return (t1, t2, t3) + } + + public static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4) + -> (T1, T2, T3, T4) { + return (t1, t2, t3, t4) + } + + public static func buildBlock( + _ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5 + ) -> (T1, T2, T3, T4, T5) { + return (t1, t2, t3, t4, t5) + } + + public static func buildDo(_ value: T) -> T { return value } + public static func buildIf(_ value: T?) -> T? { return value } +} + +public protocol ProtocolWithBuilderProperty { + associatedtype Assoc + + // CHECK: @TupleBuilder var myVar: Self.Assoc { get } + @TupleBuilder var myVar: Assoc { get } +} diff --git a/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/DeclarationFragments.swift b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Basic.swift similarity index 81% rename from test/SymbolGraph/Symbols/Mixins/DeclarationFragments/DeclarationFragments.swift rename to test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Basic.swift index 423f5d73cf92b..2c46cf5c7c853 100644 --- a/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/DeclarationFragments.swift +++ b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Basic.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) -// RUN: %target-build-swift %s -module-name DeclarationFragments -emit-module -emit-module-path %t/ -// RUN: %target-swift-symbolgraph-extract -module-name DeclarationFragments -I %t -pretty-print -output-dir %t -// RUN: %FileCheck %s --input-file %t/DeclarationFragments.symbols.json +// RUN: %target-build-swift %s -module-name Basic -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name Basic -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/Basic.symbols.json public func foo(f: @escaping () -> (), ext int: Int = 2, s: S) {} diff --git a/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Properties/ComputedProperties.swift b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Properties/ComputedProperties.swift new file mode 100644 index 0000000000000..250bbb694268a --- /dev/null +++ b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Properties/ComputedProperties.swift @@ -0,0 +1,162 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name ComputedProperties -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name ComputedProperties -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/ComputedProperties.symbols.json --check-prefix=XFULL +// RUN: %FileCheck %s --input-file %t/ComputedProperties.symbols.json --check-prefix=XSUBHEADING +// RUN: %FileCheck %s --input-file %t/ComputedProperties.symbols.json --check-prefix=YFULL +// RUN: %FileCheck %s --input-file %t/ComputedProperties.symbols.json --check-prefix=YSUBHEADING + +public struct S { + // We should show { get set } here for the + // full declaration, but not for subheadings. + public var x: Int { + get { return 7 } + set {} + } + public private(set) var y: Int { + get { return 7 } + set {} + } +} + +// XFULL-LABEL: "precise": "s:18ComputedProperties1SV1xSivp" +// XFULL: "declarationFragments": [ +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "keyword", +// XFULL-NEXT: "spelling": "var" +// XFULL-NEXT: }, +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "text", +// XFULL-NEXT: "spelling": " " +// XFULL-NEXT: }, +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "identifier", +// XFULL-NEXT: "spelling": "x" +// XFULL-NEXT: }, +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "text", +// XFULL-NEXT: "spelling": ": " +// XFULL-NEXT: }, +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "typeIdentifier", +// XFULL-NEXT: "spelling": "Int", +// XFULL-NEXT: "preciseIdentifier": "s:Si" +// XFULL-NEXT: }, +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "text", +// XFULL-NEXT: "spelling": " { " +// XFULL-NEXT: }, +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "keyword", +// XFULL-NEXT: "spelling": "get" +// XFULL-NEXT: }, +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "text", +// XFULL-NEXT: "spelling": " " +// XFULL-NEXT: }, +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "keyword", +// XFULL-NEXT: "spelling": "set" +// XFULL-NEXT: }, +// XFULL-NEXT: { +// XFULL-NEXT: "kind": "text", +// XFULL-NEXT: "spelling": " }" +// XFULL-NEXT: } +// XFULL-NEXT: ], + +// XSUBHEADING-LABEL: "precise": "s:18ComputedProperties1SV1xSivp" +// XSUBHEADING: names +// XSUBHEADING: "subHeading": [ +// XSUBHEADING-NEXT: { +// XSUBHEADING-NEXT: "kind": "keyword", +// XSUBHEADING-NEXT: "spelling": "var" +// XSUBHEADING-NEXT: }, +// XSUBHEADING-NEXT: { +// XSUBHEADING-NEXT: "kind": "text", +// XSUBHEADING-NEXT: "spelling": " " +// XSUBHEADING-NEXT: }, +// XSUBHEADING-NEXT: { +// XSUBHEADING-NEXT: "kind": "identifier", +// XSUBHEADING-NEXT: "spelling": "x" +// XSUBHEADING-NEXT: }, +// XSUBHEADING-NEXT: { +// XSUBHEADING-NEXT: "kind": "text", +// XSUBHEADING-NEXT: "spelling": ": " +// XSUBHEADING-NEXT: }, +// XSUBHEADING-NEXT: { +// XSUBHEADING-NEXT: "kind": "typeIdentifier", +// XSUBHEADING-NEXT: "spelling": "Int", +// XSUBHEADING-NEXT: "preciseIdentifier": "s:Si" +// XSUBHEADING-NEXT: } +// XSUBHEADING-NEXT: ] + +// YFULL-LABEL: "precise": "s:18ComputedProperties1SV1ySivp" +// YFULL: "declarationFragments": [ +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "keyword", +// YFULL-NEXT: "spelling": "var" +// YFULL-NEXT: }, +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "text", +// YFULL-NEXT: "spelling": " " +// YFULL-NEXT: }, +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "identifier", +// YFULL-NEXT: "spelling": "y" +// YFULL-NEXT: }, +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "text", +// YFULL-NEXT: "spelling": ": " +// YFULL-NEXT: }, +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "typeIdentifier", +// YFULL-NEXT: "spelling": "Int", +// YFULL-NEXT: "preciseIdentifier": "s:Si" +// YFULL-NEXT: }, +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "text", +// YFULL-NEXT: "spelling": " { " +// YFULL-NEXT: }, +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "keyword", +// YFULL-NEXT: "spelling": "get" +// YFULL-NEXT: }, +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "text", +// YFULL-NEXT: "spelling": " " +// YFULL-NEXT: }, +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "keyword", +// YFULL-NEXT: "spelling": "set" +// YFULL-NEXT: }, +// YFULL-NEXT: { +// YFULL-NEXT: "kind": "text", +// YFULL-NEXT: "spelling": " }" +// YFULL-NEXT: } +// YFULL-NEXT: ] + +// YSUBHEADING-LABEL: "precise": "s:18ComputedProperties1SV1ySivp" +// YSUBHEADING: names +// YSUBHEADING: "subHeading": [ +// YSUBHEADING-NEXT: { +// YSUBHEADING-NEXT: "kind": "keyword", +// YSUBHEADING-NEXT: "spelling": "var" +// YSUBHEADING-NEXT: }, +// YSUBHEADING-NEXT: { +// YSUBHEADING-NEXT: "kind": "text", +// YSUBHEADING-NEXT: "spelling": " " +// YSUBHEADING-NEXT: }, +// YSUBHEADING-NEXT: { +// YSUBHEADING-NEXT: "kind": "identifier", +// YSUBHEADING-NEXT: "spelling": "y" +// YSUBHEADING-NEXT: }, +// YSUBHEADING-NEXT: { +// YSUBHEADING-NEXT: "kind": "text", +// YSUBHEADING-NEXT: "spelling": ": " +// YSUBHEADING-NEXT: }, +// YSUBHEADING-NEXT: { +// YSUBHEADING-NEXT: "kind": "typeIdentifier", +// YSUBHEADING-NEXT: "spelling": "Int", +// YSUBHEADING-NEXT: "preciseIdentifier": "s:Si" +// YSUBHEADING-NEXT: } +// YSUBHEADING-NEXT: ] diff --git a/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Properties/ProtocolRequirements.swift b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Properties/ProtocolRequirements.swift new file mode 100644 index 0000000000000..d4e74ea184184 --- /dev/null +++ b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Properties/ProtocolRequirements.swift @@ -0,0 +1,82 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name ProtocolRequirements -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name ProtocolRequirements -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/ProtocolRequirements.symbols.json --check-prefix=FULL +// RUN: %FileCheck %s --input-file %t/ProtocolRequirements.symbols.json --check-prefix=SUBHEADING + +public protocol P { + // We should show { get set } here for the + // full declaration, but not for subheadings. + var x: Int { get set } +} + +// FULL-LABEL: "precise": "s:20ProtocolRequirements1PP1xSivp" +// FULL: "declarationFragments": [ +// FULL-NEXT: { +// FULL-NEXT: "kind": "keyword", +// FULL-NEXT: "spelling": "var" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": " " +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "identifier", +// FULL-NEXT: "spelling": "x" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": ": " +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "typeIdentifier", +// FULL-NEXT: "spelling": "Int", +// FULL-NEXT: "preciseIdentifier": "s:Si" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": " { " +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "keyword", +// FULL-NEXT: "spelling": "get" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": " " +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "keyword", +// FULL-NEXT: "spelling": "set" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": " }" +// FULL-NEXT: } +// FULL-NEXT: ] + +// SUBHEADING-LABEL: "precise": "s:20ProtocolRequirements1PP1xSivp" +// SUBHEADING: names +// SUBHEADING: "subHeading": [ +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "keyword", +// SUBHEADING-NEXT: "spelling": "var" +// SUBHEADING-NEXT: }, +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "text", +// SUBHEADING-NEXT: "spelling": " " +// SUBHEADING-NEXT: }, +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "identifier", +// SUBHEADING-NEXT: "spelling": "x" +// SUBHEADING-NEXT: }, +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "text", +// SUBHEADING-NEXT: "spelling": ": " +// SUBHEADING-NEXT: }, +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "typeIdentifier", +// SUBHEADING-NEXT: "spelling": "Int", +// SUBHEADING-NEXT: "preciseIdentifier": "s:Si" +// SUBHEADING-NEXT: } +// SUBHEADING-NEXT: ] diff --git a/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Properties/Subscripts.swift b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Properties/Subscripts.swift new file mode 100644 index 0000000000000..6e05712bb16e8 --- /dev/null +++ b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Properties/Subscripts.swift @@ -0,0 +1,95 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name Subscripts -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name Subscripts -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/Subscripts.symbols.json --check-prefix=FULL +// RUN: %FileCheck %s --input-file %t/Subscripts.symbols.json --check-prefix=SUBHEADING + +public struct S { + public subscript(i: Int) -> Int { + get { + return 7 + } + set {} + } +} + +// FULL-LABEL: "precise": "s:10Subscripts1SVyS2icip" +// FULL: "declarationFragments": [ +// FULL-NEXT: { +// FULL-NEXT: "kind": "keyword", +// FULL-NEXT: "spelling": "subscript" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": "(" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "internalParam", +// FULL-NEXT: "spelling": "i" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": ": " +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "typeIdentifier", +// FULL-NEXT: "spelling": "Int", +// FULL-NEXT: "preciseIdentifier": "s:Si" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": ") -> " +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "typeIdentifier", +// FULL-NEXT: "spelling": "Int", +// FULL-NEXT: "preciseIdentifier": "s:Si" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": " { " +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "keyword", +// FULL-NEXT: "spelling": "get" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": " " +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "keyword", +// FULL-NEXT: "spelling": "set" +// FULL-NEXT: }, +// FULL-NEXT: { +// FULL-NEXT: "kind": "text", +// FULL-NEXT: "spelling": " }" +// FULL-NEXT: } +// FULL-NEXT: ] + +// SUBHEADING-LABEL: "precise": "s:10Subscripts1SVyS2icip" +// SUBHEADING: names +// SUBHEADING: "subHeading": [ +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "keyword", +// SUBHEADING-NEXT: "spelling": "subscript" +// SUBHEADING-NEXT: }, +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "text", +// SUBHEADING-NEXT: "spelling": "(" +// SUBHEADING-NEXT: }, +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "typeIdentifier", +// SUBHEADING-NEXT: "spelling": "Int", +// SUBHEADING-NEXT: "preciseIdentifier": "s:Si" +// SUBHEADING-NEXT: }, +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "text", +// SUBHEADING-NEXT: "spelling": ") -> " +// SUBHEADING-NEXT: }, +// SUBHEADING-NEXT: { +// SUBHEADING-NEXT: "kind": "typeIdentifier", +// SUBHEADING-NEXT: "spelling": "Int", +// SUBHEADING-NEXT: "preciseIdentifier": "s:Si" +// SUBHEADING-NEXT: } +// SUBHEADING-NEXT: ]