Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3565,10 +3565,6 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
/// Prepare to traverse the list of extensions.
void prepareExtensions();

/// Add loaded members from all extensions. Eagerly load any members that we
/// can't lazily load.
void addLoadedExtensions();

/// Retrieve the conformance loader (if any), and removing it in the
/// same operation. The caller is responsible for loading the
/// conformances.
Expand All @@ -3583,13 +3579,19 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
std::pair<LazyMemberLoader *, uint64_t> takeConformanceLoaderSlow();

/// A lookup table containing all of the members of this type and
/// its extensions.
/// its extensions, together with a bit indicating if the table
/// has been prepared.
///
/// The table itself is lazily constructed and updated when
/// lookupDirect() is called.
MemberLookupTable *LookupTable = nullptr;
llvm::PointerIntPair<MemberLookupTable *, 1, bool> LookupTable;

/// Get the lookup table, lazily constructing an empty table if
/// necessary.
MemberLookupTable *getLookupTable();

/// Prepare the lookup table to make it ready for lookups.
/// Does nothing when called more than once.
void prepareLookupTable();

/// Note that we have added a member into the iterable declaration context,
Expand Down
3 changes: 3 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3023,9 +3023,12 @@ TypeAliasType::TypeAliasType(TypeAliasDecl *typealias, Type parent,

// Record the substitutions.
if (substitutions) {
assert(typealias->getGenericSignature()->isEqual(
substitutions.getGenericSignature()));
Bits.TypeAliasType.HasSubstitutionMap = true;
*getTrailingObjects<SubstitutionMap>() = substitutions;
} else {
assert(!typealias->isGenericContext());
Bits.TypeAliasType.HasSubstitutionMap = false;
}
}
Expand Down
101 changes: 45 additions & 56 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1192,10 +1192,6 @@ void LazyConformanceLoader::anchor() {}
/// Lookup table used to store members of a nominal type (and its extensions)
/// for fast retrieval.
class swift::MemberLookupTable : public ASTAllocated<swift::MemberLookupTable> {
/// The last extension that was included within the member lookup table's
/// results.
ExtensionDecl *LastExtensionIncluded = nullptr;

/// The type of the internal lookup table.
typedef llvm::DenseMap<DeclName, llvm::TinyPtrVector<ValueDecl *>>
LookupTable;
Expand All @@ -1212,9 +1208,6 @@ class swift::MemberLookupTable : public ASTAllocated<swift::MemberLookupTable> {
/// Create a new member lookup table.
explicit MemberLookupTable(ASTContext &ctx);

/// Update a lookup table with members from newly-added extensions.
void updateLookupTable(NominalTypeDecl *nominal);

/// Add the given member to the lookup table.
void addMember(Decl *members);

Expand Down Expand Up @@ -1250,12 +1243,6 @@ class swift::MemberLookupTable : public ASTAllocated<swift::MemberLookupTable> {
}

void dump(llvm::raw_ostream &os) const {
os << "LastExtensionIncluded:\n";
if (LastExtensionIncluded)
LastExtensionIncluded->printContext(os, 2);
else
os << " nullptr\n";

os << "Lookup:\n ";
for (auto &pair : Lookup) {
pair.getFirst().print(os);
Expand Down Expand Up @@ -1357,42 +1344,32 @@ void MemberLookupTable::addMembers(DeclRange members) {
}
}

void MemberLookupTable::updateLookupTable(NominalTypeDecl *nominal) {
// If the last extension we included is the same as the last known extension,
// we're already up-to-date.
if (LastExtensionIncluded == nominal->LastExtension)
void NominalTypeDecl::addedExtension(ExtensionDecl *ext) {
if (!LookupTable.getInt())
return;

// Add members from each of the extensions that we have not yet visited.
for (auto next = LastExtensionIncluded
? LastExtensionIncluded->NextExtension.getPointer()
: nominal->FirstExtension;
next;
(LastExtensionIncluded = next,next = next->NextExtension.getPointer())) {
addMembers(next->getMembers());
}
}

void NominalTypeDecl::addedExtension(ExtensionDecl *ext) {
if (!LookupTable) return;
auto *table = LookupTable.getPointer();
assert(table);

if (ext->hasLazyMembers()) {
LookupTable->addMembers(ext->getCurrentMembersWithoutLoading());
LookupTable->clearLazilyCompleteCache();
table->addMembers(ext->getCurrentMembersWithoutLoading());
table->clearLazilyCompleteCache();
} else {
LookupTable->addMembers(ext->getMembers());
table->addMembers(ext->getMembers());
}
}

void NominalTypeDecl::addedMember(Decl *member) {
// If we have a lookup table, add the new member to it. If not, we'll pick up
// this member when we first create the table.
auto *vd = dyn_cast<ValueDecl>(member);
auto *lookup = LookupTable;
if (!vd || !lookup)
if (!vd || !LookupTable.getInt())
return;

lookup->addMember(vd);
auto *table = LookupTable.getPointer();
assert(table);

table->addMember(vd);
}

void ExtensionDecl::addedMember(Decl *member) {
Expand All @@ -1406,9 +1383,7 @@ void ExtensionDecl::addedMember(Decl *member) {
}

void NominalTypeDecl::addMemberToLookupTable(Decl *member) {
prepareLookupTable();

LookupTable->addMember(member);
getLookupTable()->addMember(member);
}

// For lack of anywhere more sensible to put it, here's a diagram of the pieces
Expand Down Expand Up @@ -1506,37 +1481,52 @@ populateLookupTableEntryFromExtensions(ASTContext &ctx,
}
}

MemberLookupTable *NominalTypeDecl::getLookupTable() {
if (!LookupTable.getPointer()) {
auto &ctx = getASTContext();
LookupTable.setPointer(new (ctx) MemberLookupTable(ctx));
}

return LookupTable.getPointer();
}

void NominalTypeDecl::prepareLookupTable() {
// If we have already allocated the lookup table, then there's nothing further
// If we have already prepared the lookup table, then there's nothing further
// to do.
if (LookupTable) {
if (LookupTable.getInt())
return;
}

// Otherwise start the first fill.
auto &ctx = getASTContext();
LookupTable = new (ctx) MemberLookupTable(ctx);
auto *table = getLookupTable();

// Otherwise start the first fill.
if (hasLazyMembers()) {
assert(!hasUnparsedMembers());
LookupTable->addMembers(getCurrentMembersWithoutLoading());
table->addMembers(getCurrentMembersWithoutLoading());
} else {
LookupTable->addMembers(getMembers());
table->addMembers(getMembers());
}
}

void NominalTypeDecl::addLoadedExtensions() {
// Note: this calls prepareExtensions()
for (auto e : getExtensions()) {
// If we can lazy-load this extension, only take the members we've loaded
// so far.
//
// FIXME: This should be 'e->hasLazyMembers()' but that crashes` because
// some imported extensions don't have a Clang node, and only support
// LazyMemberLoader::loadAllMembers() and not
// LazyMemberLoader::loadNamedMembers().
if (e->wasDeserialized() || e->hasClangNode()) {
LookupTable->addMembers(e->getCurrentMembersWithoutLoading());
table->addMembers(e->getCurrentMembersWithoutLoading());
continue;
}

// Else, load all the members into the table.
LookupTable->addMembers(e->getMembers());
table->addMembers(e->getMembers());
}

// Any extensions added after this point will add their members to the
// lookup table.
LookupTable.setInt(true);
}

static TinyPtrVector<ValueDecl *>
Expand Down Expand Up @@ -1592,12 +1582,12 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,

decl->prepareLookupTable();

// If we're allowed to load extensions, call addLoadedExtensions to ensure we
// properly invalidate the lazily-complete cache for any extensions brought in
// by modules loaded after-the-fact. This can happen with the LLDB REPL.
decl->addLoadedExtensions();
// Call prepareExtensions() to ensure we properly invalidate the
// lazily-complete cache for any extensions brought in by modules
// loaded after-the-fact. This can happen with the LLDB REPL.
decl->prepareExtensions();

auto &Table = *decl->LookupTable;
auto &Table = *decl->getLookupTable();
if (!useNamedLazyMemberLoading) {
// Make sure we have the complete list of members (in this nominal and in
// all extensions).
Expand All @@ -1606,7 +1596,6 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
for (auto E : decl->getExtensions())
(void)E->getMembers();

Table.updateLookupTable(decl);
} else if (!Table.isLazilyComplete(name.getBaseName())) {
DeclBaseName baseName(name.getBaseName());

Expand Down
2 changes: 1 addition & 1 deletion lib/AST/RequirementMachine/RequirementLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
}

/// This request primarily emits diagnostics about typealiases and associated
/// type declarations that override another associate type, and can better be
/// type declarations that override another associated type, and can better be
/// expressed as requirements in the 'where' clause.
///
/// It also implements a compatibility behavior where sometimes typealiases in
Expand Down
10 changes: 3 additions & 7 deletions lib/IDE/CompletionLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1684,14 +1684,10 @@ void CompletionLookup::addTypeAliasRef(const TypeAliasDecl *TAD,
Builder.addBaseName(TAD->getName().str());
if (auto underlyingType = TAD->getUnderlyingType()) {
if (underlyingType->hasError()) {
Type parentType;
if (auto nominal = TAD->getDeclContext()->getSelfNominalTypeDecl()) {
parentType = nominal->getDeclaredInterfaceType();
}
addTypeAnnotation(Builder,
TypeAliasType::get(const_cast<TypeAliasDecl *>(TAD),
parentType, SubstitutionMap(),
underlyingType));
TAD->isGeneric()
? TAD->getUnboundGenericType()
: TAD->getDeclaredInterfaceType());

} else {
addTypeAnnotation(Builder, underlyingType);
Expand Down
3 changes: 1 addition & 2 deletions lib/Sema/ImportResolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1060,8 +1060,7 @@ ScopedImportLookupRequest::evaluate(Evaluator &evaluator,
emittedDiag.emplace(ctx.Diags.diagnose(
importLoc, diag::imported_decl_is_wrong_kind_typealias,
typealias->getDescriptiveKind(),
TypeAliasType::get(typealias, Type(), SubstitutionMap(),
typealias->getUnderlyingType()),
typealias->getDeclaredInterfaceType(),
getImportKindString(importKind)));
} else {
emittedDiag.emplace(ctx.Diags.diagnose(
Expand Down
2 changes: 0 additions & 2 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3376,8 +3376,6 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,

aliasDecl->setImplicit();
aliasDecl->setSynthesized();
if (type->hasError())
aliasDecl->setInvalid();

// Inject the typealias into the nominal decl that conforms to the protocol.
if (auto nominal = DC->getSelfNominalTypeDecl()) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4623,7 +4623,7 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module,

auto *aliasDecl = dyn_cast<TypeAliasDecl>(member);
if (aliasDecl) {
if (aliasDecl->getGenericParams()) {
if (aliasDecl->isGeneric()) {
return UnboundGenericType::get(
aliasDecl, baseTy,
aliasDecl->getASTContext());
Expand All @@ -4647,7 +4647,7 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module,
if (baseTy->is<ErrorType>())
return ErrorType::get(memberType);

subs = baseTy->getContextSubstitutionMap(module, member->getDeclContext());
subs = baseTy->getMemberSubstitutionMap(module, member);
resultType = memberType.subst(subs);
} else {
resultType = memberType;
Expand Down
11 changes: 11 additions & 0 deletions test/Generics/where_clause_contextually_generic_decls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ struct Container<T> {
// expected-error@-1 {{invalid redeclaration of 'NestedAlias}}
typealias NestedAlias2 = T.Magnitude where T: FixedWidthInteger

typealias NestedAlias3 = T.Element where T: Sequence

class NestedClass where T: Equatable {}
}

Expand Down Expand Up @@ -154,3 +156,12 @@ _ = Container<Bool>.NestedClass.self
_ = Container<String>.NestedStruct.self
_ = Container<Array<UInt8>>.NestedStruct2.self
_ = Container<Array<Double>>.NestedStruct2.NestedEnum.self

// Make sure the substitution here actually succeeds instead of producing an ErrorType
func sameType<T>(_: T.Type, _: T.Type) {}
sameType(Container<Array<Int>>.NestedAlias3.self, Int.self)
sameType(Container<Array<Bool>>.NestedAlias3.self, Int.self)
// expected-error@-1 {{cannot convert value of type 'Int.Type' to expected argument type 'Container<Array<Bool>>.NestedAlias3.Type' (aka 'Bool.Type')}}

sameType(Container<Array<Int>>.NestedAlias3.self, Bool.self)
// expected-error@-1 {{cannot convert value of type 'Bool.Type' to expected argument type 'Container<Array<Int>>.NestedAlias3.Type' (aka 'Int.Type')}}
2 changes: 1 addition & 1 deletion test/ImportResolution/import-specific-fixits.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import struct DeclsUsedWrongly.Choice // expected-error {{'Choice' was imported
import struct DeclsUsedWrongly.Callback // expected-error {{type alias 'Callback' (aka '() -> ()') cannot be imported as 'struct'}} {{8-14=typealias}}
import var DeclsUsedWrongly.Callback // expected-error {{'Callback' was imported as 'var', but is a type}} {{8-11=typealias}}

import struct DeclsUsedWrongly.Pair // expected-error {{type alias 'Pair' (aka '(T, T)') cannot be imported as 'struct'}} {{8-14=typealias}}
import struct DeclsUsedWrongly.Pair // expected-error {{type alias 'Pair<T>' (aka '(T, T)') cannot be imported as 'struct'}} {{8-14=typealias}}
import var DeclsUsedWrongly.Pair // expected-error {{'Pair' was imported as 'var', but is a type}} {{8-11=typealias}}

import struct Swift.print // expected-error {{'print' was imported as 'struct', but is a function}} {{8-14=func}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ protocol P {

struct Type<Param> {}
extension Type: P where Param: P, Param.A == Type<Param> {
// expected-error@-1 6{{extension of generic struct 'Type' has self-referential generic requirements}}
// expected-note@-2 6{{through reference here}}
// expected-error@-1 5{{extension of generic struct 'Type' has self-referential generic requirements}}
// expected-note@-2 5{{through reference here}}
// expected-error@-3 {{type 'Type<Param>' does not conform to protocol 'P'}}
typealias A = Param
// expected-note@-1 2{{through reference here}}
Expand Down