static InFlightDiagnostic diagnoseTypoCorrection(TypeChecker &tc, DeclNameLoc loc, ValueDecl *decl) { if (auto var = dyn_cast<VarDecl>(decl)) { // Suggest 'self' at the use point instead of pointing at the start // of the function. if (var->isSelfParameter()) return tc.diagnose(loc.getBaseNameLoc(), diag::note_typo_candidate, decl->getName().str()); } if (!decl->getLoc().isValid() && decl->getDeclContext()->isTypeContext()) { Decl *parentDecl = dyn_cast<ExtensionDecl>(decl->getDeclContext()); if (!parentDecl) parentDecl = cast<NominalTypeDecl>(decl->getDeclContext()); if (parentDecl->getLoc().isValid()) { StringRef kind = (isa<VarDecl>(decl) ? "property" : isa<ConstructorDecl>(decl) ? "initializer" : isa<FuncDecl>(decl) ? "method" : "member"); return tc.diagnose(parentDecl, diag::note_typo_candidate_implicit_member, decl->getName().str(), kind); } } return tc.diagnose(decl, diag::note_typo_candidate, decl->getName().str()); }
Type DerivedConformance::deriveCaseIterable(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *targetDecl, AssociatedTypeDecl *assocType) { // Conformance can't be synthesized in an extension. auto caseIterableProto = tc.Context.getProtocol(KnownProtocolKind::CaseIterable); auto caseIterableType = caseIterableProto->getDeclaredType(); if (targetDecl != parentDecl) { tc.diagnose(parentDecl->getLoc(), diag::cannot_synthesize_in_extension, caseIterableType); return nullptr; } // We can only synthesize CaseIterable for enums. auto enumDecl = dyn_cast<EnumDecl>(targetDecl); if (!enumDecl) return nullptr; // Check that we can actually derive CaseIterable for this type. if (!canDeriveConformance(targetDecl)) return nullptr; if (assocType->getName() == tc.Context.Id_AllCases) { return deriveCaseIterable_AllCases(tc, parentDecl, enumDecl); } tc.diagnose(assocType->getLoc(), diag::broken_case_iterable_requirement); return nullptr; }
static InFlightDiagnostic diagnoseTypoCorrection(TypeChecker &tc, DeclNameLoc loc, ValueDecl *decl) { if (auto var = dyn_cast<VarDecl>(decl)) { // Suggest 'self' at the use point instead of pointing at the start // of the function. if (var->isSelfParameter()) return tc.diagnose(loc.getBaseNameLoc(), diag::note_typo_candidate, decl->getName().str()); } return tc.diagnose(decl, diag::note_typo_candidate, decl->getName().str()); }
/// Returns whether the given type has a valid nested \c CodingKeys enum. /// /// If the type has an invalid \c CodingKeys entity, produces diagnostics to /// complain about the error. In this case, the error result will be true -- in /// the case where we don't have a valid CodingKeys enum and have produced /// diagnostics here, we don't want to then attempt to synthesize a CodingKeys /// enum. /// /// \param tc The typechecker to use in validating {En,Decodable} conformance. /// /// \param target The type decl whose nested \c CodingKeys type to validate. /// /// \param proto The {En,De}codable protocol to ensure the properties matching /// the keys conform to. /// /// \returns A \c CodingKeysValidity value representing the result of the check. static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc, NominalTypeDecl *target, ProtocolDecl *proto) { auto &C = tc.Context; auto codingKeysDecls = target->lookupDirect(DeclName(C.Id_CodingKeys)); if (codingKeysDecls.empty()) return CodingKeysValidity(/*hasType=*/false, /*isValid=*/true); // Only ill-formed code would produce multiple results for this lookup. // This would get diagnosed later anyway, so we're free to only look at the // first result here. auto result = codingKeysDecls.front(); auto *codingKeysTypeDecl = dyn_cast<TypeDecl>(result); if (!codingKeysTypeDecl) { tc.diagnose(result->getLoc(), diag::codable_codingkeys_type_is_not_an_enum_here, proto->getDeclaredType()); return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); } // CodingKeys may be a typealias. If so, follow the alias to its canonical // type. auto codingKeysType = codingKeysTypeDecl->getDeclaredInterfaceType(); if (isa<TypeAliasDecl>(codingKeysTypeDecl)) { codingKeysTypeDecl = codingKeysType->getAnyNominal(); } // Ensure that the type we found conforms to the CodingKey protocol. auto *codingKeyProto = C.getProtocol(KnownProtocolKind::CodingKey); if (!tc.conformsToProtocol(codingKeysType, codingKeyProto, target->getDeclContext(), ConformanceCheckFlags::Used)) { tc.diagnose(codingKeysTypeDecl->getLoc(), diag::codable_codingkeys_type_does_not_conform_here, proto->getDeclaredType()); return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); } // CodingKeys must be an enum for synthesized conformance. auto *codingKeysEnum = dyn_cast<EnumDecl>(codingKeysTypeDecl); if (!codingKeysEnum) { tc.diagnose(codingKeysTypeDecl->getLoc(), diag::codable_codingkeys_type_is_not_an_enum_here, proto->getDeclaredType()); return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); } bool valid = validateCodingKeysEnum(tc, codingKeysEnum, target, proto); return CodingKeysValidity(/*hasType=*/true, /*isValid=*/valid); }
Type DerivedConformance::deriveRawRepresentable(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *type, AssociatedTypeDecl *assocType) { // Check preconditions. These should already have been diagnosed by // type-checking but we may still get here after recovery. // The type must be an enum. auto enumDecl = dyn_cast<EnumDecl>(type); if (!enumDecl) return nullptr; // It must have a valid raw type. if (!enumDecl->hasRawType()) return nullptr; if (!enumDecl->getInherited().empty() && enumDecl->getInherited().front().isError()) return nullptr; // There must be enum elements. if (enumDecl->getAllElements().empty()) return nullptr; for (auto elt : enumDecl->getAllElements()) tc.validateDecl(elt); if (assocType->getName() == tc.Context.Id_RawValue) { return deriveRawRepresentable_Raw(tc, parentDecl, enumDecl); } tc.diagnose(assocType->getLoc(), diag::broken_raw_representable_requirement); return nullptr; }
// Suggest a default value via ?? <default value> static void offerDefaultValueUnwrapFixit(TypeChecker &TC, DeclContext *DC, Expr *expr) { auto diag = TC.diagnose(expr->getLoc(), diag::unwrap_with_default_value); // Figure out what we need to parenthesize. bool needsParensInside = exprNeedsParensBeforeAddingNilCoalescing(TC, DC, expr); bool needsParensOutside = exprNeedsParensAfterAddingNilCoalescing(TC, DC, expr, expr); llvm::SmallString<2> insertBefore; llvm::SmallString<32> insertAfter; if (needsParensOutside) { insertBefore += "("; } if (needsParensInside) { insertBefore += "("; insertAfter += ")"; } insertAfter += " ?? <" "#default value#" ">"; if (needsParensOutside) insertAfter += ")"; if (!insertBefore.empty()) { diag.fixItInsert(expr->getStartLoc(), insertBefore); } diag.fixItInsertAfter(expr->getEndLoc(), insertAfter); }
/// getInfixData - If the specified expression is an infix binary /// operator, return its infix operator attributes. static InfixData getInfixData(TypeChecker &TC, DeclContext *DC, Expr *E) { if (auto *ifExpr = dyn_cast<IfExpr>(E)) { // Ternary has fixed precedence. assert(!ifExpr->isFolded() && "already folded if expr in sequence?!"); (void)ifExpr; return InfixData(IntrinsicPrecedences::IfExpr, Associativity::Right, /*assignment*/ false); } if (auto *assign = dyn_cast<AssignExpr>(E)) { // Assignment has fixed precedence. assert(!assign->isFolded() && "already folded assign expr in sequence?!"); (void)assign; return InfixData(IntrinsicPrecedences::AssignExpr, Associativity::Right, /*assignment*/ true); } if (auto *as = dyn_cast<ExplicitCastExpr>(E)) { // 'as' and 'is' casts have fixed precedence. assert(!as->isFolded() && "already folded 'as' expr in sequence?!"); (void)as; return InfixData(IntrinsicPrecedences::ExplicitCastExpr, Associativity::None, /*assignment*/ false); } if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { SourceFile *SF = DC->getParentSourceFile(); Identifier name = DRE->getDecl()->getName(); bool isCascading = DC->isCascadingContextForLookup(true); if (InfixOperatorDecl *op = SF->lookupInfixOperator(name, isCascading, E->getLoc())) return op->getInfixData(); } if (OverloadedDeclRefExpr *OO = dyn_cast<OverloadedDeclRefExpr>(E)) { SourceFile *SF = DC->getParentSourceFile(); Identifier name = OO->getDecls()[0]->getName(); bool isCascading = DC->isCascadingContextForLookup(true); if (InfixOperatorDecl *op = SF->lookupInfixOperator(name, isCascading, E->getLoc())) return op->getInfixData(); } // If E is already an ErrorExpr, then we've diagnosed it as invalid already, // otherwise emit an error. if (!isa<ErrorExpr>(E)) TC.diagnose(E->getLoc(), diag::unknown_binop); // Recover with an infinite-precedence left-associative operator. return InfixData((unsigned char)~0U, Associativity::Left, /*assignment*/ false); }
static InFlightDiagnostic noteTypoCorrection(TypeChecker &tc, DeclNameLoc loc, ValueDecl *decl, bool wasClaimed) { if (auto var = dyn_cast<VarDecl>(decl)) { // Suggest 'self' at the use point instead of pointing at the start // of the function. if (var->isSelfParameter()) { if (wasClaimed) { // We don't need an extra note for this case because the programmer // knows what 'self' refers to. return InFlightDiagnostic(); } return tc.diagnose(loc.getBaseNameLoc(), diag::note_typo_candidate, var->getName().str()); } } if (Decl *parentDecl = findExplicitParentForImplicitDecl(decl)) { StringRef kind = (isa<VarDecl>(decl) ? "property" : isa<ConstructorDecl>(decl) ? "initializer" : isa<FuncDecl>(decl) ? "method" : "member"); return tc.diagnose(parentDecl, wasClaimed ? diag::implicit_member_declared_here : diag::note_typo_candidate_implicit_member, decl->getBaseName().userFacingName(), kind); } if (wasClaimed) { return tc.diagnose(decl, diag::decl_declared_here, decl->getBaseName()); } else { return tc.diagnose(decl, diag::note_typo_candidate, decl->getBaseName().userFacingName()); } }
static bool canSynthesizeRawRepresentable(TypeChecker &tc, Decl *parentDecl, EnumDecl *enumDecl) { // It must have a valid raw type. Type rawType = enumDecl->getRawType(); if (!rawType) return false; auto parentDC = cast<DeclContext>(parentDecl); rawType = ArchetypeBuilder::mapTypeIntoContext(parentDC, rawType); if (!enumDecl->getInherited().empty() && enumDecl->getInherited().front().isError()) return false; // The raw type must be Equatable, so that we have a suitable ~= for synthesized switch statements. auto equatableProto = tc.getProtocol(enumDecl->getLoc(), KnownProtocolKind::Equatable); if (!equatableProto) return false; if (!tc.conformsToProtocol(rawType, equatableProto, enumDecl, None)) { SourceLoc loc = enumDecl->getInherited()[0].getSourceRange().Start; tc.diagnose(loc, diag::enum_raw_type_not_equatable, rawType); return false; } // There must be enum elements. if (enumDecl->getAllElements().empty()) return false; // Have the type-checker validate that: // - the enum elements all have the same type // - they all match the enum type for (auto elt : enumDecl->getAllElements()) { tc.validateDecl(elt); if (elt->isInvalid()) { return false; } } // If it meets all of those requirements, we can synthesize RawRepresentable conformance. return true; }
Type DerivedConformance::deriveRawRepresentable(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *type, AssociatedTypeDecl *assocType) { // We can only synthesize RawRepresentable for enums. auto enumDecl = dyn_cast<EnumDecl>(type); if (!enumDecl) return nullptr; // Check other preconditions for synthesized conformance. if (!canSynthesizeRawRepresentable(tc, parentDecl, enumDecl)) return nullptr; if (assocType->getName() == tc.Context.Id_RawValue) { return deriveRawRepresentable_Raw(tc, parentDecl, enumDecl); } tc.diagnose(assocType->getLoc(), diag::broken_raw_representable_requirement); return nullptr; }
// For a generic requirement in a protocol, make sure that the requirement // set didn't add any requirements to Self or its associated types. static bool checkProtocolSelfRequirements(GenericSignature *sig, ValueDecl *decl, TypeChecker &TC) { // For a generic requirement in a protocol, make sure that the requirement // set didn't add any requirements to Self or its associated types. if (auto *proto = dyn_cast<ProtocolDecl>(decl->getDeclContext())) { auto protoSelf = proto->getSelfInterfaceType(); for (auto req : sig->getRequirements()) { // If one of the types in the requirement is dependent on a non-Self // type parameter, this requirement is okay. if (!isSelfDerivedOrConcrete(protoSelf, req.getFirstType()) || !isSelfDerivedOrConcrete(protoSelf, req.getSecondType())) continue; // The conformance of 'Self' to the protocol is okay. if (req.getKind() == RequirementKind::Conformance && req.getSecondType()->getAs<ProtocolType>()->getDecl() == proto && req.getFirstType()->is<GenericTypeParamType>()) continue; TC.diagnose(decl, TC.Context.LangOpts.EffectiveLanguageVersion[0] >= 4 ? diag::requirement_restricts_self : diag::requirement_restricts_self_swift3, decl->getDescriptiveKind(), decl->getFullName(), req.getFirstType().getString(), static_cast<unsigned>(req.getKind()), req.getSecondType().getString()); if (TC.Context.LangOpts.EffectiveLanguageVersion[0] >= 4) return true; } } return false; }
/// Validates the given CodingKeys enum decl by ensuring its cases are a 1-to-1 /// match with the stored vars of the given type. /// /// \param tc The typechecker to use in validating {En,De}codable conformance. /// /// \param codingKeysDecl The \c CodingKeys enum decl to validate. /// /// \param target The nominal type decl to validate the \c CodingKeys against. /// /// \param proto The {En,De}codable protocol to validate all the keys conform /// to. static bool validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl, NominalTypeDecl *target, ProtocolDecl *proto) { // Look through all var decls in the given type. // * Filter out lazy/computed vars (currently already done by // getStoredProperties). // * Filter out ones which are present in the given decl (by name). // // If any of the entries in the CodingKeys decl are not present in the type // by name, then this decl doesn't match. // If there are any vars left in the type which don't have a default value // (for Decodable), then this decl doesn't match. // Here we'll hold on to properties by name -- when we've validated a property // against its CodingKey entry, it will get removed. llvm::SmallDenseMap<Identifier, VarDecl *, 8> properties; for (auto *varDecl : target->getStoredProperties(/*skipInaccessible=*/true)) { properties[varDecl->getName()] = varDecl; } bool propertiesAreValid = true; for (auto elt : codingKeysDecl->getAllElements()) { auto it = properties.find(elt->getName()); if (it == properties.end()) { tc.diagnose(elt->getLoc(), diag::codable_extraneous_codingkey_case_here, elt->getName()); // TODO: Investigate typo-correction here; perhaps the case name was // misspelled and we can provide a fix-it. propertiesAreValid = false; continue; } // We have a property to map to. Ensure it's {En,De}codable. auto conformance = varConformsToCodable(tc, target->getDeclContext(), it->second, proto); switch (conformance) { case Conforms: // The property was valid. Remove it from the list. properties.erase(it); break; case DoesNotConform: tc.diagnose(it->second->getLoc(), diag::codable_non_conforming_property_here, proto->getDeclaredType(), it->second->getType()); LLVM_FALLTHROUGH; case TypeNotValidated: // We don't produce a diagnostic for a type which failed to validate. // This will produce a diagnostic elsewhere anyway. propertiesAreValid = false; continue; } } if (!propertiesAreValid) return false; // If there are any remaining properties which the CodingKeys did not cover, // we can skip them on encode. On decode, though, we can only skip them if // they have a default value. if (!properties.empty() && proto == tc.Context.getProtocol(KnownProtocolKind::Decodable)) { for (auto it = properties.begin(); it != properties.end(); ++it) { if (it->second->getParentInitializer() != nullptr) { // Var has a default value. continue; } propertiesAreValid = false; tc.diagnose(it->second->getLoc(), diag::codable_non_decoded_property_here, proto->getDeclaredType(), it->first); } } return propertiesAreValid; }
static void bindExtensionDecl(ExtensionDecl *ED, TypeChecker &TC) { if (ED->getExtendedType()) return; // If we didn't parse a type, fill in an error type and bail out. if (!ED->getExtendedTypeLoc().getTypeRepr()) { ED->setInvalid(); ED->getExtendedTypeLoc().setInvalidType(TC.Context); return; } auto dc = ED->getDeclContext(); // Validate the representation. // FIXME: Perform some kind of "shallow" validation here? TypeResolutionOptions options; options |= TR_AllowUnboundGenerics; options |= TR_ExtensionBinding; if (TC.validateType(ED->getExtendedTypeLoc(), dc, options)) { ED->setInvalid(); return; } // Dig out the extended type. auto extendedType = ED->getExtendedType(); // Hack to allow extending a generic typealias. if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) { if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) { auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); if (extendedNominal) { extendedType = extendedNominal->getDeclaredType(); ED->getExtendedTypeLoc().setType(extendedType); } } } // Handle easy cases. // Cannot extend a metatype. if (extendedType->is<AnyMetatypeType>()) { TC.diagnose(ED->getLoc(), diag::extension_metatype, extendedType) .highlight(ED->getExtendedTypeLoc().getSourceRange()); ED->setInvalid(); ED->getExtendedTypeLoc().setInvalidType(TC.Context); return; } // Cannot extend a bound generic type. if (extendedType->isSpecialized()) { TC.diagnose(ED->getLoc(), diag::extension_specialization, extendedType->getAnyNominal()->getName()) .highlight(ED->getExtendedTypeLoc().getSourceRange()); ED->setInvalid(); ED->getExtendedTypeLoc().setInvalidType(TC.Context); return; } // Dig out the nominal type being extended. NominalTypeDecl *extendedNominal = extendedType->getAnyNominal(); if (!extendedNominal) { TC.diagnose(ED->getLoc(), diag::non_nominal_extension, extendedType) .highlight(ED->getExtendedTypeLoc().getSourceRange()); ED->setInvalid(); ED->getExtendedTypeLoc().setInvalidType(TC.Context); return; } assert(extendedNominal && "Should have the nominal type being extended"); // If the extended type is generic or is a protocol. Clone or create // the generic parameters. if (extendedNominal->isGenericContext()) { if (auto proto = dyn_cast<ProtocolDecl>(extendedNominal)) { // For a protocol extension, build the generic parameter list. ED->setGenericParams(proto->createGenericParams(ED)); } else { // Clone the existing generic parameter list. ED->setGenericParams( cloneGenericParams(TC.Context, ED, extendedNominal->getGenericParamsOfContext())); } } // If we have a trailing where clause, deal with it now. // For now, trailing where clauses are only permitted on protocol extensions. if (auto trailingWhereClause = ED->getTrailingWhereClause()) { if (!extendedNominal->isGenericContext()) { // Only generic and protocol types are permitted to have // trailing where clauses. TC.diagnose(ED, diag::extension_nongeneric_trailing_where, extendedType) .highlight(trailingWhereClause->getSourceRange()); ED->setTrailingWhereClause(nullptr); } else { // Merge the trailing where clause into the generic parameter list. // FIXME: Long-term, we'd like clients to deal with the trailing where // clause explicitly, but for now it's far more direct to represent // the trailing where clause as part of the requirements. ED->getGenericParams()->addTrailingWhereClause( TC.Context, trailingWhereClause->getWhereLoc(), trailingWhereClause->getRequirements()); } } extendedNominal->addExtension(ED); }
/// All generic parameters of a generic function must be referenced in the /// declaration's type, otherwise we have no way to infer them. static void checkReferencedGenericParams(GenericContext *dc, GenericSignature *sig, TypeChecker &TC) { auto *genericParams = dc->getGenericParams(); if (!genericParams) return; auto *decl = cast<ValueDecl>(dc->getInnermostDeclarationDeclContext()); // A helper class to collect referenced generic type parameters // and dependent member types. class ReferencedGenericTypeWalker : public TypeWalker { SmallPtrSet<CanType, 4> ReferencedGenericParams; public: ReferencedGenericTypeWalker() {} Action walkToTypePre(Type ty) override { // Find generic parameters or dependent member types. // Once such a type is found, don't recurse into its children. if (!ty->hasTypeParameter()) return Action::SkipChildren; if (ty->isTypeParameter()) { ReferencedGenericParams.insert(ty->getCanonicalType()); return Action::SkipChildren; } return Action::Continue; } SmallPtrSet<CanType, 4> &getReferencedGenericParams() { return ReferencedGenericParams; } }; // Collect all generic params referenced in parameter types and // return type. ReferencedGenericTypeWalker paramsAndResultWalker; auto *funcTy = decl->getInterfaceType()->castTo<GenericFunctionType>(); funcTy->getInput().walk(paramsAndResultWalker); funcTy->getResult().walk(paramsAndResultWalker); // Set of generic params referenced in parameter types, // return type or requirements. auto &referencedGenericParams = paramsAndResultWalker.getReferencedGenericParams(); // Check if at least one of the generic params in the requirement refers // to an already referenced generic parameter. If this is the case, // then the other type is also considered as referenced, because // it is used to put requirements on the first type. auto reqTypesVisitor = [&referencedGenericParams](Requirement req) -> bool { Type first; Type second; switch (req.getKind()) { case RequirementKind::Superclass: case RequirementKind::SameType: second = req.getSecondType(); LLVM_FALLTHROUGH; case RequirementKind::Conformance: case RequirementKind::Layout: first = req.getFirstType(); break; } // Collect generic parameter types referenced by types used in a requirement. ReferencedGenericTypeWalker walker; if (first && first->hasTypeParameter()) first.walk(walker); if (second && second->hasTypeParameter()) second.walk(walker); auto &genericParamsUsedByRequirementTypes = walker.getReferencedGenericParams(); // If at least one of the collected generic types or a root generic // parameter of dependent member types is known to be referenced by // parameter types, return types or other types known to be "referenced", // then all the types used in the requirement are considered to be // referenced, because they are used to defined something that is known // to be referenced. bool foundNewReferencedGenericParam = false; if (std::any_of(genericParamsUsedByRequirementTypes.begin(), genericParamsUsedByRequirementTypes.end(), [&referencedGenericParams](CanType t) { assert(t->isTypeParameter()); return referencedGenericParams.find( t->getRootGenericParam() ->getCanonicalType()) != referencedGenericParams.end(); })) { std::for_each(genericParamsUsedByRequirementTypes.begin(), genericParamsUsedByRequirementTypes.end(), [&referencedGenericParams, &foundNewReferencedGenericParam](CanType t) { // Add only generic type parameters, but ignore any // dependent member types, because requirement // on a dependent member type does not provide enough // information to infer the base generic type // parameter. if (!t->is<GenericTypeParamType>()) return; if (referencedGenericParams.insert(t).second) foundNewReferencedGenericParam = true; }); } return foundNewReferencedGenericParam; }; ArrayRef<Requirement> requirements; auto FindReferencedGenericParamsInRequirements = [&requirements, sig, &reqTypesVisitor] { requirements = sig->getRequirements(); // Try to find new referenced generic parameter types in requirements until // we reach a fix point. We need to iterate until a fix point, because we // may have e.g. chains of same-type requirements like: // not-yet-referenced-T1 == not-yet-referenced-T2.DepType2, // not-yet-referenced-T2 == not-yet-referenced-T3.DepType3, // not-yet-referenced-T3 == referenced-T4.DepType4. // When we process the first of these requirements, we don't know yet that // T2 // will be referenced, because T3 will be referenced, // because T3 == T4.DepType4. while (true) { bool foundNewReferencedGenericParam = false; for (auto req : requirements) { if (reqTypesVisitor(req)) foundNewReferencedGenericParam = true; } if (!foundNewReferencedGenericParam) break; } }; // Find the depth of the function's own generic parameters. unsigned fnGenericParamsDepth = genericParams->getDepth(); // Check that every generic parameter type from the signature is // among referencedGenericParams. for (auto *genParam : sig->getGenericParams()) { auto *paramDecl = genParam->getDecl(); if (paramDecl->getDepth() != fnGenericParamsDepth) continue; if (!referencedGenericParams.count(genParam->getCanonicalType())) { // Lazily search for generic params that are indirectly used in the // function signature. Do it only if there is a generic parameter // that is not known to be referenced yet. if (requirements.empty()) { FindReferencedGenericParamsInRequirements(); // Nothing to do if this generic parameter is considered to be // referenced after analyzing the requirements from the generic // signature. if (referencedGenericParams.count(genParam->getCanonicalType())) continue; } // Produce an error that this generic parameter cannot be bound. TC.diagnose(paramDecl->getLoc(), diag::unreferenced_generic_parameter, paramDecl->getNameStr()); decl->setInterfaceType(ErrorType::get(TC.Context)); decl->setInvalid(); } } }