From 8c3f154258837606e3af658bac516bab0852d823 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 16:02:17 -0700 Subject: [PATCH 1/8] [NFC] Wean SILParser off of TypeLocs It was just using them as a currency type because performTypeLocChecking accepted them as a parameter. Cleaning up performTypeLocChecking is something that needs to be done independently of this changeset, so for now just encapsulate the use of TypeLocs as much as possible and use TypeRepr instead. --- lib/SIL/Parser/ParseSIL.cpp | 124 +++++++++++++++++------------------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index f08dbc88235fc..90603b27bfbf3 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -174,7 +174,7 @@ namespace { /// A callback to be invoked every time a type was deserialized. std::function ParsedTypeCallback; - bool performTypeLocChecking(TypeLoc &T, bool IsSILType, + Type performTypeLocChecking(TypeRepr *TyR, bool IsSILType, GenericEnvironment *GenericEnv = nullptr); void convertRequirements(SILFunction *F, ArrayRef From, @@ -868,17 +868,15 @@ void SILParser::convertRequirements(SILFunction *F, IdentTypeReprLookup PerformLookup(P); // Use parser lexical scopes to resolve references // to the generic parameters. - auto ResolveToInterfaceType = [&](TypeLoc Ty) -> Type { - Ty.getTypeRepr()->walk(PerformLookup); - performTypeLocChecking(Ty, /* IsSIL */ false); - assert(Ty.getType()); - return Ty.getType()->mapTypeOutOfContext(); + auto ResolveToInterfaceType = [&](TypeRepr *Ty) -> Type { + Ty->walk(PerformLookup); + return performTypeLocChecking(Ty, /* IsSIL */ false)->mapTypeOutOfContext(); }; for (auto &Req : From) { if (Req.getKind() == RequirementReprKind::SameType) { - auto FirstType = ResolveToInterfaceType(Req.getFirstTypeLoc()); - auto SecondType = ResolveToInterfaceType(Req.getSecondTypeLoc()); + auto FirstType = ResolveToInterfaceType(Req.getFirstTypeRepr()); + auto SecondType = ResolveToInterfaceType(Req.getSecondTypeRepr()); Requirement ConvertedRequirement(RequirementKind::SameType, FirstType, SecondType); To.push_back(ConvertedRequirement); @@ -886,8 +884,8 @@ void SILParser::convertRequirements(SILFunction *F, } if (Req.getKind() == RequirementReprKind::TypeConstraint) { - auto Subject = ResolveToInterfaceType(Req.getSubjectLoc()); - auto Constraint = ResolveToInterfaceType(Req.getConstraintLoc()); + auto Subject = ResolveToInterfaceType(Req.getSubjectRepr()); + auto Constraint = ResolveToInterfaceType(Req.getConstraintRepr()); Requirement ConvertedRequirement(RequirementKind::Conformance, Subject, Constraint); To.push_back(ConvertedRequirement); @@ -895,7 +893,7 @@ void SILParser::convertRequirements(SILFunction *F, } if (Req.getKind() == RequirementReprKind::LayoutConstraint) { - auto Subject = ResolveToInterfaceType(Req.getSubjectLoc()); + auto Subject = ResolveToInterfaceType(Req.getSubjectRepr()); Requirement ConvertedRequirement(RequirementKind::Layout, Subject, Req.getLayoutConstraint()); To.push_back(ConvertedRequirement); @@ -1094,14 +1092,16 @@ static bool parseDeclSILOptional(bool *isTransparent, return false; } -bool SILParser::performTypeLocChecking(TypeLoc &T, bool IsSILType, +Type SILParser::performTypeLocChecking(TypeRepr *T, bool IsSILType, GenericEnvironment *GenericEnv) { if (GenericEnv == nullptr) GenericEnv = ContextGenericEnv; - return swift::performTypeLocChecking(P.Context, T, + TypeLoc loc(T); + (void) swift::performTypeLocChecking(P.Context, loc, /*isSILMode=*/true, IsSILType, GenericEnv, &P.SF); + return loc.getType(); } /// Find the top-level ValueDecl or Module given a name. @@ -1155,17 +1155,17 @@ static ValueDecl *lookupMember(Parser &P, Type Ty, DeclBaseName Name, bool SILParser::parseASTType(CanType &result, GenericEnvironment *env) { ParserResult parsedType = P.parseType(); if (parsedType.isNull()) return true; - TypeLoc loc = parsedType.get(); - if (performTypeLocChecking(loc, /*IsSILType=*/ false, env)) + auto resolvedType = performTypeLocChecking(parsedType.get(), /*IsSILType=*/ false, env); + if (resolvedType->hasError()) return true; if (env) - result = loc.getType()->mapTypeOutOfContext()->getCanonicalType(); + result = resolvedType->mapTypeOutOfContext()->getCanonicalType(); else - result = loc.getType()->getCanonicalType(); + result = resolvedType->getCanonicalType(); // Invoke the callback on the parsed type. - ParsedTypeCallback(loc.getType()); + ParsedTypeCallback(resolvedType); return false; } @@ -1244,16 +1244,16 @@ bool SILParser::parseSILType(SILType &Result, ParsedGenericEnv = env; // Apply attributes to the type. - TypeLoc Ty = P.applyAttributeToType(TyR.get(), attrs, specifier, specifierLoc); - - if (performTypeLocChecking(Ty, /*IsSILType=*/true, OuterGenericEnv)) + auto *attrRepr = P.applyAttributeToType(TyR.get(), attrs, specifier, specifierLoc); + auto Ty = performTypeLocChecking(attrRepr, /*IsSILType=*/true, OuterGenericEnv); + if (Ty->hasError()) return true; - Result = SILType::getPrimitiveType(Ty.getType()->getCanonicalType(), + Result = SILType::getPrimitiveType(Ty->getCanonicalType(), category); // Invoke the callback on the parsed type. - ParsedTypeCallback(Ty.getType()); + ParsedTypeCallback(Ty); return false; } @@ -1644,34 +1644,34 @@ bool SILParser::parseSILBBArgsAtBranch(SmallVector &Args, /// /// FIXME: This is a hack to work around the lack of a DeclContext for /// witness tables. -static void bindProtocolSelfInTypeRepr(TypeLoc &TL, ProtocolDecl *proto) { - if (auto typeRepr = TL.getTypeRepr()) { - // AST walker to update 'Self' references. - class BindProtocolSelf : public ASTWalker { - ProtocolDecl *proto; - GenericTypeParamDecl *selfParam; - Identifier selfId; - - public: - BindProtocolSelf(ProtocolDecl *proto) - : proto(proto), - selfParam(proto->getProtocolSelfType()->getDecl()), - selfId(proto->getASTContext().Id_Self) { - } +static void bindProtocolSelfInTypeRepr(TypeRepr *typeRepr, ProtocolDecl *proto) { + assert(typeRepr); - virtual bool walkToTypeReprPre(TypeRepr *T) override { - if (auto ident = dyn_cast(T)) { - auto firstComponent = ident->getComponentRange().front(); - if (firstComponent->getNameRef().isSimpleName(selfId)) - firstComponent->setValue(selfParam, proto); - } + // AST walker to update 'Self' references. + class BindProtocolSelf : public ASTWalker { + ProtocolDecl *proto; + GenericTypeParamDecl *selfParam; + Identifier selfId; - return true; + public: + BindProtocolSelf(ProtocolDecl *proto) + : proto(proto), + selfParam(proto->getProtocolSelfType()->getDecl()), + selfId(proto->getASTContext().Id_Self) { + } + + virtual bool walkToTypeReprPre(TypeRepr *T) override { + if (auto ident = dyn_cast(T)) { + auto firstComponent = ident->getComponentRange().front(); + if (firstComponent->getNameRef().isSimpleName(selfId)) + firstComponent->setValue(selfParam, proto); } - }; - typeRepr->walk(BindProtocolSelf(proto)); - } + return true; + } + }; + + typeRepr->walk(BindProtocolSelf(proto)); } /// Parse the substitution list for an apply instruction or @@ -1693,12 +1693,13 @@ bool SILParser::parseSubstitutions(SmallVectorImpl &parsed, ParserResult TyR = P.parseType(); if (TyR.isNull()) return true; - TypeLoc Ty = TyR.get(); if (defaultForProto) - bindProtocolSelfInTypeRepr(Ty, defaultForProto); - if (performTypeLocChecking(Ty, /*IsSILType=*/ false, GenericEnv)) + bindProtocolSelfInTypeRepr(TyR.get(), defaultForProto); + + auto Ty = performTypeLocChecking(TyR.get(), /*IsSILType=*/ false, GenericEnv); + if (Ty->hasError()) return true; - parsed.push_back({Loc, Ty.getType()}); + parsed.push_back({Loc, Ty}); } while (P.consumeIf(tok::comma)); // Consume the closing '>'. @@ -2090,31 +2091,27 @@ bool SILParser::parseSILDeclRef(SILDeclRef &Member, bool FnTypeRequired) { GenericsScope.reset(); if (TyR.isNull()) return true; - TypeLoc Ty = TyR.get(); // The type can be polymorphic. GenericEnvironment *genericEnv = nullptr; if (auto fnType = dyn_cast(TyR.get())) { if (auto generics = fnType->getGenericParams()) { - assert(!Ty.wasValidated() && Ty.getType().isNull()); - genericEnv = handleSILGenericParams(generics, &P.SF); fnType->setGenericEnvironment(genericEnv); } if (auto generics = fnType->getPatternGenericParams()) { - assert(!Ty.wasValidated() && Ty.getType().isNull()); - genericEnv = handleSILGenericParams(generics, &P.SF); fnType->setPatternGenericEnvironment(genericEnv); } } - if (performTypeLocChecking(Ty, /*IsSILType=*/ false, genericEnv)) + auto Ty = performTypeLocChecking(TyR.get(), /*IsSILType=*/ false, genericEnv); + if (Ty->hasError()) return true; // Pick the ValueDecl that has the right type. ValueDecl *TheDecl = nullptr; - auto declTy = Ty.getType()->getCanonicalType(); + auto declTy = Ty->getCanonicalType(); for (unsigned I = 0, E = values.size(); I < E; ++I) { auto *decl = values[I]; @@ -6306,14 +6303,13 @@ ProtocolConformanceRef SILParser::parseProtocolConformanceHelper( ParserResult TyR = P.parseType(); if (TyR.isNull()) return ProtocolConformanceRef(); - TypeLoc Ty = TyR.get(); if (defaultForProto) { - bindProtocolSelfInTypeRepr(Ty, defaultForProto); + bindProtocolSelfInTypeRepr(TyR.get(), defaultForProto); } - if (performTypeLocChecking(Ty, /*IsSILType=*/ false, witnessEnv)) + auto ConformingTy = performTypeLocChecking(TyR.get(), /*IsSILType=*/ false, witnessEnv); + if (ConformingTy->hasError()) return ProtocolConformanceRef(); - auto ConformingTy = Ty.getType(); if (P.parseToken(tok::colon, diag::expected_sil_witness_colon)) return ProtocolConformanceRef(); @@ -6429,7 +6425,7 @@ static bool parseSILVTableEntry( return true; TypeLoc Ty = TyR.get(); if (isDefaultWitnessTable) - bindProtocolSelfInTypeRepr(Ty, proto); + bindProtocolSelfInTypeRepr(TyR.get(), proto); if (swift::performTypeLocChecking(P.Context, Ty, /*isSILMode=*/false, /*isSILType=*/false, @@ -6490,7 +6486,7 @@ static bool parseSILVTableEntry( return true; TypeLoc Ty = TyR.get(); if (isDefaultWitnessTable) - bindProtocolSelfInTypeRepr(Ty, proto); + bindProtocolSelfInTypeRepr(TyR.get(), proto); if (swift::performTypeLocChecking(P.Context, Ty, /*isSILMode=*/false, /*isSILType=*/false, From 8be08b16a8368680ed5781cfa3de869e629ee0f1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 16:03:43 -0700 Subject: [PATCH 2/8] [NFC] Remove Trivial Projections from TypeLocs in RequirementRepr --- lib/AST/ASTWalker.cpp | 6 +++--- lib/Sema/TypeCheckDeclPrimary.cpp | 2 +- lib/Sema/TypeCheckType.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 57d4cda33ff27..e121f3528db75 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -1345,15 +1345,15 @@ class Traversal : public ASTVisitorisEqual(proto->getSelfInterfaceType())) { auto &diags = proto->getASTContext().Diags; - diags.diagnose(reqRepr->getSubjectLoc().getLoc(), + diags.diagnose(reqRepr->getSubjectRepr()->getLoc(), diag::protocol_where_clause_self_requirement); } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 3f368011f8aa1..9d142ebf69ad7 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -3804,9 +3804,9 @@ class UnsupportedProtocolVisitor void visitRequirements(ArrayRef reqts) { for (auto reqt : reqts) { if (reqt.getKind() == RequirementReprKind::SameType) { - if (auto *repr = reqt.getFirstTypeLoc().getTypeRepr()) + if (auto *repr = reqt.getFirstTypeRepr()) repr->walk(*this); - if (auto *repr = reqt.getSecondTypeLoc().getTypeRepr()) + if (auto *repr = reqt.getSecondTypeRepr()) repr->walk(*this); } } From a748d8ed7785d11ba16c15037533c2710e4de4fc Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 16:04:32 -0700 Subject: [PATCH 3/8] [NFC] Fixup RequirementRepr Printing To Use Only the Repr If a semantic representation of the RequirementRepr is needed, then it should be resolved to a Requirement and printed. --- include/swift/AST/Decl.h | 6 +++--- lib/AST/ASTDumper.cpp | 34 ++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 600042bf07563..2a7523cd69bc3 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1044,16 +1044,16 @@ class RequirementRepr { StringRef AsWrittenString; RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind, - TypeLoc FirstType, TypeLoc SecondType) + TypeRepr *FirstType, TypeRepr *SecondType) : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), FirstType(FirstType), SecondType(SecondType) { } RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind, - TypeLoc FirstType, LayoutConstraintLoc SecondLayout) + TypeRepr *FirstType, LayoutConstraintLoc SecondLayout) : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), FirstType(FirstType), SecondLayout(SecondLayout) { } - void printImpl(ASTPrinter &OS, bool AsWritten) const; + void printImpl(ASTPrinter &OS) const; public: /// Construct a new type-constraint requirement. diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 4aef9bc3905ca..a8c26677f43bc 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -121,15 +121,7 @@ void RequirementRepr::dump() const { llvm::errs() << "\n"; } -void RequirementRepr::printImpl(ASTPrinter &out, bool AsWritten) const { - auto printTy = [&](const TypeLoc &TyLoc) { - if (AsWritten && TyLoc.getTypeRepr()) { - TyLoc.getTypeRepr()->print(out, PrintOptions()); - } else { - TyLoc.getType().print(out, PrintOptions()); - } - }; - +void RequirementRepr::printImpl(ASTPrinter &out) const { auto printLayoutConstraint = [&](const LayoutConstraintLoc &LayoutConstraintLoc) { LayoutConstraintLoc.getLayoutConstraint()->print(out, PrintOptions()); @@ -137,31 +129,41 @@ void RequirementRepr::printImpl(ASTPrinter &out, bool AsWritten) const { switch (getKind()) { case RequirementReprKind::LayoutConstraint: - printTy(getSubjectLoc()); + if (auto *repr = getSubjectRepr()) { + repr->print(out, PrintOptions()); + } out << " : "; printLayoutConstraint(getLayoutConstraintLoc()); break; case RequirementReprKind::TypeConstraint: - printTy(getSubjectLoc()); + if (auto *repr = getSubjectRepr()) { + repr->print(out, PrintOptions()); + } out << " : "; - printTy(getConstraintLoc()); + if (auto *repr = getConstraintRepr()) { + repr->print(out, PrintOptions()); + } break; case RequirementReprKind::SameType: - printTy(getFirstTypeLoc()); + if (auto *repr = getFirstTypeRepr()) { + repr->print(out, PrintOptions()); + } out << " == "; - printTy(getSecondTypeLoc()); + if (auto *repr = getSecondTypeRepr()) { + repr->print(out, PrintOptions()); + } break; } } void RequirementRepr::print(raw_ostream &out) const { StreamPrinter printer(out); - printImpl(printer, /*AsWritten=*/true); + printImpl(printer); } void RequirementRepr::print(ASTPrinter &out) const { - printImpl(out, /*AsWritten=*/true); + printImpl(out); } static void printTrailingRequirements(ASTPrinter &Printer, From 10f53c07b5eb9277c494f8f42d6765bd204e26fd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 16:06:02 -0700 Subject: [PATCH 4/8] [NFC] Refactor getAdopteeSelfSameTypeConstraint This method performs a linear-ish search over all the generic requirements and tries to pull out a matching written requirement so it can provide a richer diagnostic. Unpack this search, teach it to walk resolved requirements, and clean up the code here. --- lib/Sema/TypeCheckProtocol.cpp | 74 ++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index b9cd51877744e..b674225c27244 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -3103,43 +3103,57 @@ diagnoseMissingWitnesses(MissingWitnessDiagnosisKind Kind) { /// /// \returns None if there is no such constraint; a non-empty optional that /// may have the \c RequirementRepr for the actual constraint. -static Optional +static Optional> getAdopteeSelfSameTypeConstraint(ClassDecl *selfClass, ValueDecl *witness) { auto genericSig = witness->getInnermostDeclContext()->getGenericSignatureOfContext(); if (!genericSig) return None; - for (const auto &req : genericSig->getRequirements()) { + // First, search for any bogus requirements. + auto it = llvm::find_if(genericSig->getRequirements(), + [&selfClass](const auto &req) { if (req.getKind() != RequirementKind::SameType) - continue; + return false; - if (req.getFirstType()->getAnyNominal() == selfClass || - req.getSecondType()->getAnyNominal() == selfClass) { - // Try to find the requirement-as-written. - GenericParamList *genericParams = nullptr; - - if (auto func = dyn_cast(witness)) - genericParams = func->getGenericParams(); - else if (auto subscript = dyn_cast(witness)) - genericParams = subscript->getGenericParams(); - if (genericParams) { - for (auto &req : genericParams->getRequirements()) { - if (req.getKind() != RequirementReprKind::SameType) - continue; + return req.getFirstType()->getAnyNominal() == selfClass + || req.getSecondType()->getAnyNominal() == selfClass; + }); + if (it == genericSig->getRequirements().end()) { + return None; + } - if (req.getFirstType()->getAnyNominal() == selfClass || - req.getSecondType()->getAnyNominal() == selfClass) - return &req; - } - } + // Got it! Now try to find the requirement-as-written. + GenericParamList *genericParams = nullptr; + if (auto func = dyn_cast(witness)) + genericParams = func->getGenericParams(); + else if (auto subscript = dyn_cast(witness)) + genericParams = subscript->getGenericParams(); - // Form an optional(nullptr) to indicate that we don't have the - // requirement itself. - return nullptr; - } + // A null repr indicates we don't have a valid location to diagnose. But + // at least we have a requirement we can signal is bogus. + Optional> target + = std::make_pair((RequirementRepr *)nullptr, Requirement(*it)); + if (!genericParams) { + return target; } - return None; + // Resolve and search for a written requirement to match our bogus one. + WhereClauseOwner(cast(witness), genericParams) + .visitRequirements(TypeResolutionStage::Structural, + [&](Requirement req, RequirementRepr *repr) { + if (req.getKind() != RequirementKind::SameType) { + return false; + } + + if (req.getFirstType()->getAnyNominal() != selfClass && + req.getSecondType()->getAnyNominal() != selfClass) { + return false; + } + + target.emplace(repr, req); + return true; + }); + return target; } void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement, @@ -3239,7 +3253,7 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement, }); } } else if (selfKind.requirement) { - if (auto constraint = getAdopteeSelfSameTypeConstraint(classDecl, + if (auto targetPair = getAdopteeSelfSameTypeConstraint(classDecl, witness)) { // A "Self ==" constraint works incorrectly with subclasses. Complain. auto proto = Conformance->getProtocol(); @@ -3254,11 +3268,11 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement, proto->getDeclaredType()); emitDeclaredHereIfNeeded(diags, diagLoc, witness); - if (auto requirementRepr = *constraint) { + if (auto requirementRepr = targetPair->first) { diags.diagnose(requirementRepr->getSeparatorLoc(), diag::witness_self_weaken_same_type, - requirementRepr->getFirstType(), - requirementRepr->getSecondType()) + targetPair->second.getFirstType(), + targetPair->second.getSecondType()) .fixItReplace(requirementRepr->getSeparatorLoc(), ":"); } } From 68d2d824b76b936cb488f4ea79d5f1c72031b8dc Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 16:07:27 -0700 Subject: [PATCH 5/8] [NFC] Teach BuiltinFunctionBuilder to Build Requirements There is no need to build a fake RequirementRepr if we can directly represent a the requested AnyObject conformance constraint in the generated generic signature. This removes the final user of the TypeLoc-bearing constructors of RequirementReprs. --- lib/AST/Builtins.cpp | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 32516e69f9a5b..8c3bf3e7ec5d2 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -431,26 +431,13 @@ createGenericParam(ASTContext &ctx, const char *name, unsigned index) { /// Create a generic parameter list with multiple generic parameters. static GenericParamList *getGenericParams(ASTContext &ctx, - unsigned numParameters, - bool isAnyObject) { + unsigned numParameters) { assert(numParameters <= llvm::array_lengthof(GenericParamNames)); - SmallVector genericParams; + SmallVector genericParams; for (unsigned i = 0; i != numParameters; ++i) genericParams.push_back(createGenericParam(ctx, GenericParamNames[i], i)); - - if (isAnyObject) { - CanType ao = ctx.getAnyObjectType(); - SmallVector req; - req.push_back(RequirementRepr::getTypeConstraint(TypeLoc::withoutLoc(genericParams[0]->getInterfaceType()), SourceLoc(), - TypeLoc::withoutLoc(ao))); - - auto paramList = GenericParamList::create(ctx, SourceLoc(), genericParams, - SourceLoc(), req, SourceLoc()); - return paramList; - } - auto paramList = GenericParamList::create(ctx, SourceLoc(), genericParams, SourceLoc()); return paramList; @@ -474,9 +461,15 @@ namespace { public: BuiltinFunctionBuilder(ASTContext &ctx, unsigned numGenericParams = 1, - bool isAnyObject = false) + bool wantsAdditionalAnyObjectRequirement = false) : Context(ctx) { - TheGenericParamList = getGenericParams(ctx, numGenericParams, isAnyObject); + TheGenericParamList = getGenericParams(ctx, numGenericParams); + if (wantsAdditionalAnyObjectRequirement) { + Requirement req(RequirementKind::Conformance, + TheGenericParamList->getParams()[0]->getInterfaceType(), + ctx.getAnyObjectType()); + addedRequirements.push_back(req); + } for (auto gp : TheGenericParamList->getParams()) { genericParamTypes.push_back( gp->getDeclaredInterfaceType()->castTo()); From b8d0cf342cf74213c4bbbe2eb89e22184ef26dad Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 16:08:34 -0700 Subject: [PATCH 6/8] [NFC] Only Resolve TypeReprs If Given a RequirementRepr Resolve the written type instead of the semantic type since that's the only data these requests will have access to once RequirementRepr is made completely syntactic. --- lib/AST/NameLookup.cpp | 28 +++++++++------------------- lib/Sema/TypeCheckGeneric.cpp | 20 +++++--------------- 2 files changed, 14 insertions(+), 34 deletions(-) diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 36311b7f85644..156c511cb590e 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -857,8 +857,6 @@ SelfBoundsFromWhereClauseRequest::evaluate( if (auto identTypeRepr = dyn_cast(typeRepr)) isSelfLHS = (identTypeRepr->getNameRef().getBaseIdentifier() == ctx.Id_Self); - } else if (Type type = req.getSubject()) { - isSelfLHS = type->isEqual(dc->getSelfInterfaceType()); } if (!isSelfLHS) continue; @@ -867,8 +865,6 @@ SelfBoundsFromWhereClauseRequest::evaluate( DirectlyReferencedTypeDecls rhsDecls; if (auto typeRepr = req.getConstraintRepr()) { rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, lookupDC); - } else if (Type type = req.getConstraint()) { - rhsDecls = directReferencesForType(type); } SmallVector modulesFound; @@ -899,30 +895,24 @@ TypeDeclsFromWhereClauseRequest::evaluate(Evaluator &evaluator, ASTContext &ctx = ext->getASTContext(); TinyPtrVector result; + auto resolve = [&](TypeRepr *typeRepr) { + auto decls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext); + result.insert(result.end(), decls.begin(), decls.end()); + }; for (const auto &req : ext->getGenericParams()->getTrailingRequirements()) { - auto resolve = [&](TypeLoc loc) { - DirectlyReferencedTypeDecls decls; - if (auto *typeRepr = loc.getTypeRepr()) - decls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext); - else if (Type type = loc.getType()) - decls = directReferencesForType(type); - - result.insert(result.end(), decls.begin(), decls.end()); - }; - switch (req.getKind()) { case RequirementReprKind::TypeConstraint: - resolve(req.getSubjectLoc()); - resolve(req.getConstraintLoc()); + resolve(req.getSubjectRepr()); + resolve(req.getConstraintRepr()); break; case RequirementReprKind::SameType: - resolve(req.getFirstTypeLoc()); - resolve(req.getSecondTypeLoc()); + resolve(req.getFirstTypeRepr()); + resolve(req.getSecondTypeRepr()); break; case RequirementReprKind::LayoutConstraint: - resolve(req.getSubjectLoc()); + resolve(req.getSubjectRepr()); break; } } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index ee60881ea9634..c18cc16e3d965 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -931,21 +931,11 @@ RequirementRequest::evaluate(Evaluator &evaluator, llvm_unreachable("No clients care about this. Use mapTypeIntoContext()"); } - auto resolveType = [&](TypeLoc &typeLoc) -> Type { - Type result; - if (auto typeRepr = typeLoc.getTypeRepr()) - result = resolution->resolveType(typeRepr); - else - result = typeLoc.getType(); - - return result ? result : ErrorType::get(owner.dc->getASTContext()); - }; - auto &reqRepr = getRequirement(); switch (reqRepr.getKind()) { case RequirementReprKind::TypeConstraint: { - Type subject = resolveType(reqRepr.getSubjectLoc()); - Type constraint = resolveType(reqRepr.getConstraintLoc()); + Type subject = resolution->resolveType(reqRepr.getSubjectRepr()); + Type constraint = resolution->resolveType(reqRepr.getConstraintRepr()); return Requirement(constraint->getClassOrBoundGenericClass() ? RequirementKind::Superclass : RequirementKind::Conformance, @@ -954,12 +944,12 @@ RequirementRequest::evaluate(Evaluator &evaluator, case RequirementReprKind::SameType: return Requirement(RequirementKind::SameType, - resolveType(reqRepr.getFirstTypeLoc()), - resolveType(reqRepr.getSecondTypeLoc())); + resolution->resolveType(reqRepr.getFirstTypeRepr()), + resolution->resolveType(reqRepr.getSecondTypeRepr())); case RequirementReprKind::LayoutConstraint: return Requirement(RequirementKind::Layout, - resolveType(reqRepr.getSubjectLoc()), + resolution->resolveType(reqRepr.getSubjectRepr()), reqRepr.getLayoutConstraint()); } llvm_unreachable("unhandled kind"); From d197f9d1abf7f6ab88b157d36cc38fe806b86d44 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 16:09:32 -0700 Subject: [PATCH 7/8] [NFC] Make RequirementRequest Cached In preparation for the removal of the TypeLocs here, cache down the resulting Requirement from a RequirementRepr. --- include/swift/AST/TypeCheckRequests.h | 6 +-- include/swift/AST/TypeCheckerTypeIDZone.def | 2 +- lib/AST/TypeCheckRequests.cpp | 54 --------------------- 3 files changed, 3 insertions(+), 59 deletions(-) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 75392765ce473..46d6b5ae0810a 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -441,7 +441,7 @@ class RequirementRequest : public SimpleRequest { + RequestFlags::Cached> { public: using SimpleRequest::SimpleRequest; @@ -464,10 +464,8 @@ class RequirementRequest : // Cycle handling. void noteCycleStep(DiagnosticEngine &diags) const; - // Separate caching. + // Caching. bool isCached() const; - Optional getCachedResult() const; - void cacheResult(Requirement value) const; }; /// Generate the USR for the given declaration. diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 4df761af7c2d2..2acdda4869312 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -176,7 +176,7 @@ SWIFT_REQUEST(TypeChecker, ProtocolRequiresClassRequest, bool(ProtocolDecl *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, RequirementRequest, Requirement(WhereClauseOwner, unsigned, TypeResolutionStage), - SeparatelyCached, HasNearestLocation) + Cached, HasNearestLocation) SWIFT_REQUEST(TypeChecker, RequirementSignatureRequest, ArrayRef(ProtocolDecl *), SeparatelyCached, NoLocationInfo) diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 6ecd7c87e2b50..41276bd6d1956 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -459,60 +459,6 @@ bool RequirementRequest::isCached() const { return std::get<2>(getStorage()) == TypeResolutionStage::Interface; } -Optional RequirementRequest::getCachedResult() const { - auto &reqRepr = getRequirement(); - switch (reqRepr.getKind()) { - case RequirementReprKind::TypeConstraint: - if (!reqRepr.getSubjectLoc().wasValidated() || - !reqRepr.getConstraintLoc().wasValidated()) - return None; - - return Requirement(reqRepr.getConstraint()->getClassOrBoundGenericClass() - ? RequirementKind::Superclass - : RequirementKind::Conformance, - reqRepr.getSubject(), - reqRepr.getConstraint()); - - case RequirementReprKind::SameType: - if (!reqRepr.getFirstTypeLoc().wasValidated() || - !reqRepr.getSecondTypeLoc().wasValidated()) - return None; - - return Requirement(RequirementKind::SameType, reqRepr.getFirstType(), - reqRepr.getSecondType()); - - case RequirementReprKind::LayoutConstraint: - if (!reqRepr.getSubjectLoc().wasValidated()) - return None; - - return Requirement(RequirementKind::Layout, reqRepr.getSubject(), - reqRepr.getLayoutConstraint()); - } - llvm_unreachable("unhandled kind"); -} - -void RequirementRequest::cacheResult(Requirement value) const { - auto &reqRepr = getRequirement(); - switch (value.getKind()) { - case RequirementKind::Conformance: - case RequirementKind::Superclass: - reqRepr.getSubjectLoc().setType(value.getFirstType()); - reqRepr.getConstraintLoc().setType(value.getSecondType()); - break; - - case RequirementKind::SameType: - reqRepr.getFirstTypeLoc().setType(value.getFirstType()); - reqRepr.getSecondTypeLoc().setType(value.getSecondType()); - break; - - case RequirementKind::Layout: - reqRepr.getSubjectLoc().setType(value.getFirstType()); - reqRepr.getLayoutConstraintLoc() - .setLayoutConstraint(value.getLayoutConstraint()); - break; - } -} - //----------------------------------------------------------------------------// // DefaultTypeRequest. //----------------------------------------------------------------------------// From b9427b0a88c1a0a985c7020965be2e31ed153be7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 16:17:30 -0700 Subject: [PATCH 8/8] [NFC] Strip RequirementRepr of its TypeLocs Now that the previous commits have removed the data dependencies on TypeLoc, remove the TypeLoc and replace it with a TypeRepr. This makes RequirementRepr a purely syntactic object once again. --- include/swift/AST/Decl.h | 89 +++++----------------------------------- lib/AST/Decl.cpp | 9 ++++ 2 files changed, 19 insertions(+), 79 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 2a7523cd69bc3..8b372835d08b1 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1030,12 +1030,12 @@ class RequirementRepr { SourceLoc SeparatorLoc; RequirementReprKind Kind : 2; bool Invalid : 1; - TypeLoc FirstType; + TypeRepr *FirstType; /// The second element represents the right-hand side of the constraint. /// It can be e.g. a type or a layout constraint. union { - TypeLoc SecondType; + TypeRepr *SecondType; LayoutConstraintLoc SecondLayout; }; @@ -1064,9 +1064,9 @@ class RequirementRepr { /// this requirement was implied. /// \param Constraint The protocol or protocol composition to which the /// subject must conform, or superclass from which the subject must inherit. - static RequirementRepr getTypeConstraint(TypeLoc Subject, + static RequirementRepr getTypeConstraint(TypeRepr *Subject, SourceLoc ColonLoc, - TypeLoc Constraint) { + TypeRepr *Constraint) { return { ColonLoc, RequirementReprKind::TypeConstraint, Subject, Constraint }; } @@ -1076,9 +1076,9 @@ class RequirementRepr { /// \param EqualLoc The location of the '==' in the same-type constraint, or /// an invalid location if this requirement was implied. /// \param SecondType The second type. - static RequirementRepr getSameType(TypeLoc FirstType, + static RequirementRepr getSameType(TypeRepr *FirstType, SourceLoc EqualLoc, - TypeLoc SecondType) { + TypeRepr *SecondType) { return { EqualLoc, RequirementReprKind::SameType, FirstType, SecondType }; } @@ -1090,7 +1090,7 @@ class RequirementRepr { /// this requirement was implied. /// \param Layout The layout requirement to which the /// subject must conform. - static RequirementRepr getLayoutConstraint(TypeLoc Subject, + static RequirementRepr getLayoutConstraint(TypeRepr *Subject, SourceLoc ColonLoc, LayoutConstraintLoc Layout) { return {ColonLoc, RequirementReprKind::LayoutConstraint, Subject, @@ -1108,25 +1108,7 @@ class RequirementRepr { /// For a type-bound requirement, return the subject of the /// conformance relationship. - Type getSubject() const { - assert(getKind() == RequirementReprKind::TypeConstraint || - getKind() == RequirementReprKind::LayoutConstraint); - return FirstType.getType(); - } - TypeRepr *getSubjectRepr() const { - assert(getKind() == RequirementReprKind::TypeConstraint || - getKind() == RequirementReprKind::LayoutConstraint); - return FirstType.getTypeRepr(); - } - - TypeLoc &getSubjectLoc() { - assert(getKind() == RequirementReprKind::TypeConstraint || - getKind() == RequirementReprKind::LayoutConstraint); - return FirstType; - } - - const TypeLoc &getSubjectLoc() const { assert(getKind() == RequirementReprKind::TypeConstraint || getKind() == RequirementReprKind::LayoutConstraint); return FirstType; @@ -1134,22 +1116,7 @@ class RequirementRepr { /// For a type-bound requirement, return the protocol or to which /// the subject conforms or superclass it inherits. - Type getConstraint() const { - assert(getKind() == RequirementReprKind::TypeConstraint); - return SecondType.getType(); - } - TypeRepr *getConstraintRepr() const { - assert(getKind() == RequirementReprKind::TypeConstraint); - return SecondType.getTypeRepr(); - } - - TypeLoc &getConstraintLoc() { - assert(getKind() == RequirementReprKind::TypeConstraint); - return SecondType; - } - - const TypeLoc &getConstraintLoc() const { assert(getKind() == RequirementReprKind::TypeConstraint); return SecondType; } @@ -1170,43 +1137,13 @@ class RequirementRepr { } /// Retrieve the first type of a same-type requirement. - Type getFirstType() const { - assert(getKind() == RequirementReprKind::SameType); - return FirstType.getType(); - } - TypeRepr *getFirstTypeRepr() const { - assert(getKind() == RequirementReprKind::SameType); - return FirstType.getTypeRepr(); - } - - TypeLoc &getFirstTypeLoc() { - assert(getKind() == RequirementReprKind::SameType); - return FirstType; - } - - const TypeLoc &getFirstTypeLoc() const { assert(getKind() == RequirementReprKind::SameType); return FirstType; } /// Retrieve the second type of a same-type requirement. - Type getSecondType() const { - assert(getKind() == RequirementReprKind::SameType); - return SecondType.getType(); - } - TypeRepr *getSecondTypeRepr() const { - assert(getKind() == RequirementReprKind::SameType); - return SecondType.getTypeRepr(); - } - - TypeLoc &getSecondTypeLoc() { - assert(getKind() == RequirementReprKind::SameType); - return SecondType; - } - - const TypeLoc &getSecondTypeLoc() const { assert(getKind() == RequirementReprKind::SameType); return SecondType; } @@ -1217,19 +1154,13 @@ class RequirementRepr { return SeparatorLoc; } - SourceRange getSourceRange() const { - if (getKind() == RequirementReprKind::LayoutConstraint) - return SourceRange(FirstType.getSourceRange().Start, - SecondLayout.getSourceRange().End); - return SourceRange(FirstType.getSourceRange().Start, - SecondType.getSourceRange().End); - } + SourceRange getSourceRange() const; /// Retrieve the first or subject type representation from the \c repr, /// or \c nullptr if \c repr is null. static TypeRepr *getFirstTypeRepr(const RequirementRepr *repr) { if (!repr) return nullptr; - return repr->FirstType.getTypeRepr(); + return repr->FirstType; } /// Retrieve the second or constraint type representation from the \c repr, @@ -1238,7 +1169,7 @@ class RequirementRepr { if (!repr) return nullptr; assert(repr->getKind() == RequirementReprKind::TypeConstraint || repr->getKind() == RequirementReprKind::SameType); - return repr->SecondType.getTypeRepr(); + return repr->SecondType; } SWIFT_DEBUG_DUMP; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 81706cee2a48b..53bede44749f5 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -875,6 +875,15 @@ bool Decl::isWeakImported(ModuleDecl *fromModule) const { return !fromContext.isContainedIn(containingContext); } + +SourceRange RequirementRepr::getSourceRange() const { + if (getKind() == RequirementReprKind::LayoutConstraint) + return SourceRange(FirstType->getSourceRange().Start, + SecondLayout.getSourceRange().End); + return SourceRange(FirstType->getSourceRange().Start, + SecondType->getSourceRange().End); +} + GenericParamList::GenericParamList(SourceLoc LAngleLoc, ArrayRef Params, SourceLoc WhereLoc,