LookupResult TypeChecker::lookupMember(DeclContext *dc, Type type, DeclName name, NameLookupOptions options) { assert(type->mayHaveMembers()); LookupResult result; NLOptions subOptions = NL_QualifiedDefault; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::IgnoreAccessControl)) subOptions |= NL_IgnoreAccessControl; if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; if (options.contains(NameLookupFlags::IncludeAttributeImplements)) subOptions |= NL_IncludeAttributeImplements; // We handle our own overriding/shadowing filtering. subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; LookupResultBuilder builder(result, dc, options, /*memberLookup*/true); SmallVector<ValueDecl *, 4> lookupResults; dc->lookupQualified(type, name, subOptions, nullptr, lookupResults); for (auto found : lookupResults) builder.add(found, nullptr, type, /*isOuter=*/false); return result; }
LookupResult TypeChecker::lookupMember(DeclContext *dc, Type type, DeclName name, NameLookupOptions options) { assert(type->mayHaveMembers()); LookupResult result; NLOptions subOptions = NL_QualifiedDefault; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::DynamicLookup)) subOptions |= NL_DynamicLookup; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; NominalTypeDecl *nominalLookupType = type->getAnyNominal(); if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; // We handle our own overriding/shadowing filtering. subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; // Local function that performs lookup. auto doLookup = [&]() { result.clear(); LookupResultBuilder builder(*this, result, dc, options, /*memberLookup*/true); SmallVector<ValueDecl *, 4> lookupResults; dc->lookupQualified(type, name, subOptions, this, lookupResults); for (auto found : lookupResults) { builder.add(found, nominalLookupType, type); } }; doLookup(); if (result.empty()) { // If we didn't find anything, /and/ this is a nominal type, check to see // if any of the nominal's protocols are derivable and contain the // name we're looking for. (Note that we are not including extensions // here -- default derivation doesn't apply in extensions.) if (!nominalLookupType) return result; // Force the creation of any delayed members, to ensure proper member // lookup. this->forceExternalDeclMembers(nominalLookupType); // Perform the lookup again. // FIXME: This is only because forceExternalDeclMembers() might do something // interesting. doLookup(); } return result; }
LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclName name, SourceLoc loc, NameLookupOptions options) { // Determine whether we're searching from a protocol extension. bool searchingFromProtoExt = false; for (auto outerDC = dc; outerDC; outerDC = outerDC->getParent()) { if (auto ext = dyn_cast<ExtensionDecl>(outerDC)) { if (ext->getExtendedType() && ext->getExtendedType()->is<ProtocolType>()) { searchingFromProtoExt = true; break; } } } UnqualifiedLookup lookup(name, dc, this, options.contains(NameLookupFlags::KnownPrivate), loc, options.contains(NameLookupFlags::OnlyTypes), options.contains(NameLookupFlags::ProtocolMembers)); LookupResult result; bool considerProtocolMembers = options.contains(NameLookupFlags::ProtocolMembers); LookupResultBuilder builder(*this, result, dc, options, considerProtocolMembers, searchingFromProtoExt, /*memberLookup*/false); for (const auto &found : lookup.Results) { // Determine which type we looked through to find this result. Type foundInType; if (!found.getBaseDecl()) { // Not found within a type. } else if (auto baseParam = dyn_cast<ParamDecl>(found.getBaseDecl())) { auto baseDC = baseParam->getDeclContext(); if (isa<AbstractFunctionDecl>(baseDC)) baseDC = baseDC->getParent(); foundInType = baseDC->getDeclaredTypeInContext(); } else { auto baseNominal = cast<NominalTypeDecl>(found.getBaseDecl()); for (auto currentDC = dc; currentDC; currentDC = currentDC->getParent()) { if (currentDC->getAsNominalTypeOrNominalTypeExtensionContext() == baseNominal) { foundInType = currentDC->getDeclaredTypeInContext(); } } assert(foundInType && "bogus base declaration?"); } builder.add(found.getValueDecl(), found.getBaseDecl(), foundInType); } return result; }
static UnqualifiedLookup::Options convertToUnqualifiedLookupOptions(NameLookupOptions options) { UnqualifiedLookup::Options newOptions; if (options.contains(NameLookupFlags::KnownPrivate)) newOptions |= UnqualifiedLookup::Flags::KnownPrivate; if (options.contains(NameLookupFlags::ProtocolMembers)) newOptions |= UnqualifiedLookup::Flags::AllowProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessControl)) newOptions |= UnqualifiedLookup::Flags::IgnoreAccessControl; if (options.contains(NameLookupFlags::IncludeOuterResults)) newOptions |= UnqualifiedLookup::Flags::IncludeOuterResults; return newOptions; }
LookupResult TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclName name, SourceLoc loc, NameLookupOptions options) { auto ulOptions = convertToUnqualifiedLookupOptions(options) | UnqualifiedLookup::Flags::TypeLookup; { // Try lookup without ProtocolMembers first. UnqualifiedLookup lookup( name, dc, nullptr, loc, ulOptions - UnqualifiedLookup::Flags::AllowProtocolMembers); if (!lookup.Results.empty() || !options.contains(NameLookupFlags::ProtocolMembers)) { return LookupResult(lookup.Results, lookup.IndexOfFirstOuterResult); } } { // Try again, this time with protocol members. // // FIXME: Fix the problem where if NominalTypeDecl::getAllProtocols() // is called too early, we start resolving extensions -- even those // which do provide not conformances. UnqualifiedLookup lookup( name, dc, nullptr, loc, ulOptions | UnqualifiedLookup::Flags::AllowProtocolMembers); return LookupResult(lookup.Results, lookup.IndexOfFirstOuterResult); } }
LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclName name, SourceLoc loc, NameLookupOptions options) { UnqualifiedLookup lookup( name, dc, this, options.contains(NameLookupFlags::KnownPrivate), loc, options.contains(NameLookupFlags::OnlyTypes), options.contains(NameLookupFlags::ProtocolMembers), options.contains(NameLookupFlags::IgnoreAccessibility)); LookupResult result; LookupResultBuilder builder(*this, result, dc, options, /*memberLookup*/false); for (const auto &found : lookup.Results) { // Determine which type we looked through to find this result. Type foundInType; if (!found.getBaseDecl()) { // Not found within a type. } else if (auto baseParam = dyn_cast<ParamDecl>(found.getBaseDecl())) { auto baseDC = baseParam->getDeclContext(); if (isa<AbstractFunctionDecl>(baseDC)) baseDC = baseDC->getParent(); foundInType = baseDC->getDeclaredTypeInContext(); } else { auto baseNominal = cast<NominalTypeDecl>(found.getBaseDecl()); for (auto currentDC = dc; currentDC; currentDC = currentDC->getParent()) { if (currentDC->getAsNominalTypeOrNominalTypeExtensionContext() == baseNominal) { foundInType = currentDC->getDeclaredTypeInContext(); } } assert(foundInType && "bogus base declaration?"); } builder.add(found.getValueDecl(), found.getBaseDecl(), foundInType); } return result; }
SmallVector<TypeDecl *, 1> TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclName name, SourceLoc loc, NameLookupOptions options) { SmallVector<TypeDecl *, 1> decls; // Try lookup without ProtocolMembers first. UnqualifiedLookup lookup( name, dc, this, options.contains(NameLookupFlags::KnownPrivate), loc, /*OnlyTypes=*/true, /*AllowProtocolMembers=*/false, options.contains(NameLookupFlags::IgnoreAccessibility)); for (auto found : lookup.Results) decls.push_back(cast<TypeDecl>(found.getValueDecl())); if (decls.empty() && options.contains(NameLookupFlags::ProtocolMembers)) { // Try again, this time with protocol members. // // FIXME: Fix the problem where if NominalTypeDecl::getAllProtocols() // is called too early, we start resolving extensions -- even those // which do provide conformances. UnqualifiedLookup lookup( name, dc, this, options.contains(NameLookupFlags::KnownPrivate), loc, /*OnlyTypes=*/true, /*AllowProtocolMembers=*/true, options.contains(NameLookupFlags::IgnoreAccessibility)); for (auto found : lookup.Results) decls.push_back(cast<TypeDecl>(found.getValueDecl())); } return decls; }
LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, Type type, Identifier name, NameLookupOptions options) { LookupTypeResult result; // Look through an inout type. if (auto inout = type->getAs<InOutType>()) type = inout->getObjectType(); // Look through the metatype. if (auto metaT = type->getAs<AnyMetatypeType>()) type = metaT->getInstanceType(); // Callers must cope with dependent types directly. assert(!type->isTypeParameter()); // Look for members with the given name. SmallVector<ValueDecl *, 4> decls; NLOptions subOptions = NL_QualifiedDefault | NL_OnlyTypes; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; if (!dc->lookupQualified(type, name, subOptions, this, decls)) return result; // Look through the declarations, keeping only the unique type declarations. llvm::SmallPtrSet<CanType, 4> types; SmallVector<AssociatedTypeDecl *, 4> inferredAssociatedTypes; for (auto decl : decls) { auto *typeDecl = cast<TypeDecl>(decl); // FIXME: This should happen before we attempt shadowing checks. validateDecl(typeDecl); if (!typeDecl->hasType()) // FIXME: recursion-breaking hack continue; // If we're looking up a member of a protocol, we must take special care. if (typeDecl->getDeclContext()->getAsProtocolOrProtocolExtensionContext()) { // We don't allow lookups of an associated type or typealias of an // existential type, because we have no way to represent such types. // // This is diagnosed further on down in resolveNestedIdentTypeComponent(). if (type->isExistentialType()) { auto memberType = typeDecl->getInterfaceType()->getRValueInstanceType(); if (memberType->hasTypeParameter()) { // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType}); continue; } } // If we're looking up an associated type of a concrete type, // record it later for conformance checking; we might find a more // direct typealias with the same name later. if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) { if (!type->is<ArchetypeType>()) { inferredAssociatedTypes.push_back(assocType); continue; } } // We are looking up an associated type of an archetype, or a // protocol typealias or an archetype or concrete type. // // Proceed with the usual path below. } // Substitute the base into the member's type. auto memberType = substMemberTypeWithBase(dc->getParentModule(), typeDecl, type, /*isTypeReference=*/true); // FIXME: It is not clear why this substitution can fail, but the // standard library won't build without this check. if (!memberType) continue; // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType}); } if (result.Results.empty()) { // We couldn't find any normal declarations. Let's try inferring // associated types. ConformanceCheckOptions conformanceOptions; if (options.contains(NameLookupFlags::KnownPrivate)) conformanceOptions |= ConformanceCheckFlags::InExpression; for (AssociatedTypeDecl *assocType : inferredAssociatedTypes) { // If the type does not actually conform to the protocol, skip this // member entirely. auto *protocol = cast<ProtocolDecl>(assocType->getDeclContext()); ProtocolConformance *conformance = nullptr; if (!conformsToProtocol(type, protocol, dc, conformanceOptions, &conformance) || !conformance) { // FIXME: This is an error path. Should we try to recover? continue; } // Use the type witness. Type memberType = conformance->getTypeWitness(assocType, this).getReplacement(); assert(memberType && "Missing type witness?"); // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({assocType, memberType}); } } return result; }
LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, Type type, Identifier name, NameLookupOptions options) { LookupTypeResult result; // Look through an inout type. if (auto inout = type->getAs<InOutType>()) type = inout->getObjectType(); // Look through the metatype. if (auto metaT = type->getAs<AnyMetatypeType>()) type = metaT->getInstanceType(); // Callers must cope with dependent types directly. assert(!type->isTypeParameter()); // Look for members with the given name. SmallVector<ValueDecl *, 4> decls; NLOptions subOptions = NL_QualifiedDefault; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; if (!dc->lookupQualified(type, name, subOptions, this, decls)) return result; // Look through the declarations, keeping only the unique type declarations. llvm::SmallPtrSet<CanType, 4> types; SmallVector<AssociatedTypeDecl *, 4> inferredAssociatedTypes; for (auto decl : decls) { // Ignore non-types found by name lookup. auto typeDecl = dyn_cast<TypeDecl>(decl); if (!typeDecl) continue; // FIXME: This should happen before we attempt shadowing checks. validateDecl(typeDecl); if (!typeDecl->hasType()) // FIXME: recursion-breaking hack continue; // If we found a member of a protocol type when looking into a non-protocol, // non-archetype type, only include this member in the result set if // this member was used as the default definition or otherwise inferred. if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) { if (!type->is<ArchetypeType>() && !type->isExistentialType()) { inferredAssociatedTypes.push_back(assocType); continue; } } // Ignore typealiases found in protocol members. if (auto alias = dyn_cast<TypeAliasDecl>(typeDecl)) { auto aliasParent = alias->getParent(); if (aliasParent != dc && isa<ProtocolDecl>(aliasParent)) continue; } // Substitute the base into the member's type. if (Type memberType = substMemberTypeWithBase(dc->getParentModule(), typeDecl, type, /*isTypeReference=*/true)) { // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType}); } } if (result.Results.empty()) { // We couldn't find any normal declarations. Let's try inferring // associated types. ConformanceCheckOptions conformanceOptions; if (options.contains(NameLookupFlags::KnownPrivate)) conformanceOptions |= ConformanceCheckFlags::InExpression; for (AssociatedTypeDecl *assocType : inferredAssociatedTypes) { // If the type does not actually conform to the protocol, skip this // member entirely. auto *protocol = cast<ProtocolDecl>(assocType->getDeclContext()); ProtocolConformance *conformance = nullptr; if (!conformsToProtocol(type, protocol, dc, conformanceOptions, &conformance) || !conformance) { // FIXME: This is an error path. Should we try to recover? continue; } // Use the type witness. Type memberType = conformance->getTypeWitness(assocType, this).getReplacement(); assert(memberType && "Missing type witness?"); // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({assocType, memberType}); } } return result; }
LookupResult TypeChecker::lookupMember(DeclContext *dc, Type type, DeclName name, NameLookupOptions options) { LookupResult result; NLOptions subOptions = NL_QualifiedDefault; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::DynamicLookup)) subOptions |= NL_DynamicLookup; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; // Dig out the type that we'll actually be looking into, and determine // whether it is a nominal type. Type lookupType = type; if (auto lvalueType = lookupType->getAs<LValueType>()) { lookupType = lvalueType->getObjectType(); } if (auto metaType = lookupType->getAs<MetatypeType>()) { lookupType = metaType->getInstanceType(); } NominalTypeDecl *nominalLookupType = lookupType->getAnyNominal(); /// Whether to consider protocol members or not. bool considerProtocolMembers = nominalLookupType && !isa<ProtocolDecl>(nominalLookupType) && options.contains(NameLookupFlags::ProtocolMembers); if (considerProtocolMembers) subOptions |= NL_ProtocolMembers; // We handle our own overriding/shadowing filtering. subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; // We can't have tuple types here; they need to be handled elsewhere. assert(!type->is<TupleType>()); // Local function that performs lookup. auto doLookup = [&]() { result.clear(); LookupResultBuilder builder(*this, result, dc, options, considerProtocolMembers, false); SmallVector<ValueDecl *, 4> lookupResults; dc->lookupQualified(type, name, subOptions, this, lookupResults); for (auto found : lookupResults) { builder.add(found, nominalLookupType, type); } }; doLookup(); if (result.empty()) { // If we didn't find anything, /and/ this is a nominal type, check to see // if any of the nominal's protocols are derivable and contain the // name we're looking for. (Note that we are not including extensions // here -- default derivation doesn't apply in extensions.) if (!nominalLookupType) return result; // Force the creation of any delayed members, to ensure proper member // lookup. this->forceExternalDeclMembers(nominalLookupType); // Perform the lookup again. // FIXME: This is only because forceExternalDeclMembers() might do something // interesting. doLookup(); } return result; }
LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, Type type, Identifier name, NameLookupOptions options) { LookupTypeResult result; // Look for members with the given name. SmallVector<ValueDecl *, 4> decls; NLOptions subOptions = NL_QualifiedDefault | NL_OnlyTypes; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessControl)) subOptions |= NL_IgnoreAccessControl; if (!dc->lookupQualified(type, name, subOptions, nullptr, decls)) return result; // Look through the declarations, keeping only the unique type declarations. llvm::SmallPtrSet<CanType, 4> types; SmallVector<AssociatedTypeDecl *, 4> inferredAssociatedTypes; for (auto decl : decls) { auto *typeDecl = cast<TypeDecl>(decl); // FIXME: This should happen before we attempt shadowing checks. if (!typeDecl->hasInterfaceType()) { dc->getASTContext().getLazyResolver()->resolveDeclSignature(typeDecl); if (!typeDecl->hasInterfaceType()) // FIXME: recursion-breaking hack continue; } auto memberType = typeDecl->getDeclaredInterfaceType(); if (isUnsupportedMemberTypeAccess(type, typeDecl)) { // Add the type to the result set, so that we can diagnose the // reference instead of just saying the member does not exist. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType, nullptr}); continue; } // If we're looking up an associated type of a concrete type, // record it later for conformance checking; we might find a more // direct typealias with the same name later. if (typeDecl->getDeclContext()->getSelfProtocolDecl()) { if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) { if (!type->is<ArchetypeType>() && !type->isTypeParameter()) { if (options.contains(NameLookupFlags::PerformConformanceCheck)) inferredAssociatedTypes.push_back(assocType); continue; } } // FIXME: This is a hack, we should be able to remove this entire 'if' // statement once we learn how to deal with the circularity here. if (isa<TypeAliasDecl>(typeDecl) && isa<ProtocolDecl>(typeDecl->getDeclContext())) { if (!type->is<ArchetypeType>() && !type->isTypeParameter() && memberType->hasTypeParameter() && !options.contains(NameLookupFlags::PerformConformanceCheck)) { continue; } } // Nominal type members of protocols cannot be accessed with an // archetype base, because we have no way to recover the correct // substitutions. if (type->is<ArchetypeType>() && isa<NominalTypeDecl>(typeDecl)) { continue; } } // Substitute the base into the member's type. memberType = substMemberTypeWithBase(dc->getParentModule(), typeDecl, type); // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType, nullptr}); } if (result.Results.empty()) { // We couldn't find any normal declarations. Let's try inferring // associated types. ConformanceCheckOptions conformanceOptions; if (options.contains(NameLookupFlags::KnownPrivate)) conformanceOptions |= ConformanceCheckFlags::InExpression; conformanceOptions |= ConformanceCheckFlags::SkipConditionalRequirements; for (AssociatedTypeDecl *assocType : inferredAssociatedTypes) { // If the type does not actually conform to the protocol, skip this // member entirely. auto *protocol = cast<ProtocolDecl>(assocType->getDeclContext()); // If we're validating the protocol recursively, bail out. if (!protocol->hasValidSignature()) continue; auto conformance = conformsToProtocol(type, protocol, dc, conformanceOptions); if (!conformance) { // FIXME: This is an error path. Should we try to recover? continue; } // Use the type witness. auto concrete = conformance->getConcrete(); // This is the only case where NormalProtocolConformance:: // getTypeWitnessAndDecl() returns a null type. if (concrete->getState() == ProtocolConformanceState::CheckingTypeWitnesses) continue; auto lazyResolver = dc->getASTContext().getLazyResolver(); auto typeDecl = concrete->getTypeWitnessAndDecl(assocType, lazyResolver).second; assert(typeDecl && "Missing type witness?"); auto memberType = substMemberTypeWithBase(dc->getParentModule(), typeDecl, type); if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType, assocType}); } } return result; }