Skip to content

Commit 78b38cd

Browse files
authored
Merge pull request #2992 from slavapestov/protocol-typealias-fixes
2 parents af1defc + 08d5e29 commit 78b38cd

File tree

43 files changed

+567
-529
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+567
-529
lines changed

include/swift/AST/LookupKinds.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ enum NLOptions : unsigned {
6262
/// \see NL_KnownDependencyMask
6363
NL_KnownCascadingDependency = 0x80,
6464

65+
/// This lookup should only return type declarations.
66+
NL_OnlyTypes = 0x100,
67+
6568
/// This lookup is known to not add any additional dependencies to the
6669
/// primary source file.
6770
///

include/swift/AST/NameLookup.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,18 @@ class NamedDeclConsumer : public VisibleDeclConsumer {
194194
public:
195195
DeclName name;
196196
SmallVectorImpl<UnqualifiedLookupResult> &results;
197+
bool isTypeLookup;
198+
197199
NamedDeclConsumer(DeclName name,
198-
SmallVectorImpl<UnqualifiedLookupResult> &results)
199-
: name(name), results(results) {}
200+
SmallVectorImpl<UnqualifiedLookupResult> &results,
201+
bool isTypeLookup)
202+
: name(name), results(results), isTypeLookup(isTypeLookup) {}
200203

201204
virtual void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
205+
// Give clients an opportunity to filter out non-type declarations early,
206+
// to avoid circular validation.
207+
if (isTypeLookup && !isa<TypeDecl>(VD))
208+
return;
202209
if (VD->getFullName().matchesRef(name))
203210
results.push_back(UnqualifiedLookupResult(VD));
204211
}

lib/AST/Decl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,8 @@ llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS,
286286
DeclContext *Decl::getInnermostDeclContext() const {
287287
if (auto func = dyn_cast<AbstractFunctionDecl>(this))
288288
return const_cast<AbstractFunctionDecl*>(func);
289-
if (auto nominal = dyn_cast<NominalTypeDecl>(this))
290-
return const_cast<NominalTypeDecl*>(nominal);
289+
if (auto nominal = dyn_cast<GenericTypeDecl>(this))
290+
return const_cast<GenericTypeDecl*>(nominal);
291291
if (auto ext = dyn_cast<ExtensionDecl>(this))
292292
return const_cast<ExtensionDecl*>(ext);
293293
if (auto topLevel = dyn_cast<TopLevelCodeDecl>(this))

lib/AST/NameLookup.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
385385
const SourceManager &SM = Ctx.SourceMgr;
386386
DebuggerClient *DebugClient = M.getDebugClient();
387387

388-
NamedDeclConsumer Consumer(Name, Results);
388+
NamedDeclConsumer Consumer(Name, Results, IsTypeLookup);
389389

390390
Optional<bool> isCascadingUse;
391391
if (IsKnownNonCascading)
@@ -530,6 +530,8 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
530530

531531
if (AllowProtocolMembers)
532532
options |= NL_ProtocolMembers;
533+
if (IsTypeLookup)
534+
options |= NL_OnlyTypes;
533535

534536
if (!ExtendedType)
535537
ExtendedType = ErrorType::get(Ctx);
@@ -1262,6 +1264,11 @@ bool DeclContext::lookupQualified(Type type,
12621264
// Look for results within the current nominal type and its extensions.
12631265
bool currentIsProtocol = isa<ProtocolDecl>(current);
12641266
for (auto decl : current->lookupDirect(member)) {
1267+
// If we're performing a type lookup, don't even attempt to validate
1268+
// the decl if its not a type.
1269+
if ((options & NL_OnlyTypes) && !isa<TypeDecl>(decl))
1270+
continue;
1271+
12651272
// Resolve the declaration signature when we find the
12661273
// declaration.
12671274
if (typeResolver && !decl->isBeingTypeChecked()) {

lib/AST/Type.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2917,15 +2917,8 @@ TypeSubstitutionMap TypeBase::getMemberSubstitutions(const DeclContext *dc) {
29172917
// If the member is part of a protocol or extension thereof, we need
29182918
// to substitute in the type of Self.
29192919
if (dc->getAsProtocolOrProtocolExtensionContext()) {
2920-
// We only substitute into archetypes for now for protocols.
2921-
// FIXME: This seems like an odd restriction. Whatever is depending on
2922-
// this, shouldn't.
2923-
if (!baseTy->is<ArchetypeType>() && isa<ProtocolDecl>(dc))
2924-
return substitutions;
2925-
29262920
// FIXME: This feels painfully inefficient. We're creating a dense map
29272921
// for a single substitution.
2928-
substitutions[dc->getProtocolSelf()->getArchetype()] = baseTy;
29292922
substitutions[dc->getProtocolSelf()->getDeclaredType()
29302923
->getCanonicalType()->castTo<GenericTypeParamType>()]
29312924
= baseTy;

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,11 +1846,11 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
18461846
cs.addConstraint(ConstraintKind::ConformsTo, SequenceType,
18471847
sequenceProto->getDeclaredType(), Locator);
18481848

1849-
auto generatorLocator =
1849+
auto iteratorLocator =
18501850
cs.getConstraintLocator(Locator,
18511851
ConstraintLocator::SequenceIteratorProtocol);
18521852
auto elementLocator =
1853-
cs.getConstraintLocator(generatorLocator,
1853+
cs.getConstraintLocator(iteratorLocator,
18541854
ConstraintLocator::GeneratorElementType);
18551855

18561856
// Collect constraints from the element pattern.
@@ -1859,48 +1859,58 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
18591859
if (!InitType)
18601860
return true;
18611861

1862-
// Manually search for the generator witness. If no generator/element pair
1862+
// Manually search for the iterator witness. If no iterator/element pair
18631863
// exists, solve for them.
1864-
// FIXME: rename generatorType to iteratorType due to the protocol
1865-
// renaming
1866-
Type generatorType;
1864+
Type iteratorType;
18671865
Type elementType;
18681866

18691867
NameLookupOptions lookupOptions = defaultMemberTypeLookupOptions;
18701868
if (isa<AbstractFunctionDecl>(cs.DC))
18711869
lookupOptions |= NameLookupFlags::KnownPrivate;
1872-
auto member = cs.TC.lookupMemberType(cs.DC,
1873-
expr->getType()->getRValueType(),
1874-
tc.Context.Id_Iterator,
1875-
lookupOptions);
1870+
1871+
auto sequenceType = expr->getType()->getRValueType();
1872+
1873+
// If the sequence type is an existential, we should not attempt to
1874+
// look up the member type at all, since we cannot represent associated
1875+
// types of existentials.
1876+
//
1877+
// We will diagnose it later.
1878+
if (!sequenceType->isExistentialType()) {
1879+
auto member = cs.TC.lookupMemberType(cs.DC,
1880+
sequenceType,
1881+
tc.Context.Id_Iterator,
1882+
lookupOptions);
18761883

1877-
if (member) {
1878-
generatorType = member.front().second;
1879-
1880-
member = cs.TC.lookupMemberType(cs.DC,
1881-
generatorType,
1882-
tc.Context.Id_Element,
1883-
lookupOptions);
1884-
1885-
if (member)
1886-
elementType = member.front().second;
1884+
if (member) {
1885+
iteratorType = member.front().second;
1886+
1887+
member = cs.TC.lookupMemberType(cs.DC,
1888+
iteratorType,
1889+
tc.Context.Id_Element,
1890+
lookupOptions);
1891+
1892+
if (member)
1893+
elementType = member.front().second;
1894+
}
18871895
}
1888-
1896+
1897+
// If the type lookup failed, just add some constraints we can
1898+
// try to solve later.
18891899
if (elementType.isNull()) {
18901900

1891-
// Determine the generator type of the sequence.
1892-
generatorType = cs.createTypeVariable(Locator, /*options=*/0);
1901+
// Determine the iterator type of the sequence.
1902+
iteratorType = cs.createTypeVariable(Locator, /*options=*/0);
18931903
cs.addConstraint(Constraint::create(
18941904
cs, ConstraintKind::TypeMember,
1895-
SequenceType, generatorType,
1896-
tc.Context.Id_Iterator, generatorLocator));
1905+
SequenceType, iteratorType,
1906+
tc.Context.Id_Iterator, iteratorLocator));
18971907

1898-
// Determine the element type of the generator.
1908+
// Determine the element type of the iterator.
18991909
// FIXME: Should look up the type witness.
19001910
elementType = cs.createTypeVariable(Locator, /*options=*/0);
19011911
cs.addConstraint(Constraint::create(
19021912
cs, ConstraintKind::TypeMember,
1903-
generatorType, elementType,
1913+
iteratorType, elementType,
19041914
tc.Context.Id_Element, elementLocator));
19051915
}
19061916

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ namespace {
104104
/// \param foundInType The type through which we found the
105105
/// declaration.
106106
void add(ValueDecl *found, ValueDecl *base, Type foundInType) {
107-
// If we only want types and we didn't get one, bail out.
108-
if (Options.contains(NameLookupFlags::OnlyTypes) && !isa<TypeDecl>(found))
109-
return;
107+
// If we only want types, AST name lookup should not yield anything else.
108+
assert(!Options.contains(NameLookupFlags::OnlyTypes) ||
109+
isa<TypeDecl>(found));
110110

111111
ConformanceCheckOptions conformanceOptions;
112112
if (Options.contains(NameLookupFlags::KnownPrivate))
@@ -245,6 +245,8 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc,
245245
subOptions |= NL_DynamicLookup;
246246
if (options.contains(NameLookupFlags::IgnoreAccessibility))
247247
subOptions |= NL_IgnoreAccessibility;
248+
if (options.contains(NameLookupFlags::OnlyTypes))
249+
subOptions |= NL_OnlyTypes;
248250

249251
// Dig out the type that we'll actually be looking into, and determine
250252
// whether it is a nominal type.
@@ -351,37 +353,54 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
351353
validateDecl(typeDecl);
352354
if (!typeDecl->hasType()) // FIXME: recursion-breaking hack
353355
continue;
354-
355-
// If we found a member of a protocol type when looking into a non-protocol,
356-
// non-archetype type, only include this member in the result set if
357-
// this member was used as the default definition or otherwise inferred.
358-
if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) {
359-
if (!type->is<ArchetypeType>() && !type->isExistentialType()) {
360-
inferredAssociatedTypes.push_back(assocType);
361-
continue;
356+
357+
// If we're looking up a member of a protocol, we must take special care.
358+
if (typeDecl->getDeclContext()->getAsProtocolOrProtocolExtensionContext()) {
359+
// We don't allow lookups of an associated type or typealias of an
360+
// existential type, because we have no way to represent such types.
361+
//
362+
// This is diagnosed further on down in resolveNestedIdentTypeComponent().
363+
if (type->isExistentialType()) {
364+
auto memberType = typeDecl->getInterfaceType()->getRValueInstanceType();
365+
366+
if (memberType->hasTypeParameter()) {
367+
// If we haven't seen this type result yet, add it to the result set.
368+
if (types.insert(memberType->getCanonicalType()).second)
369+
result.Results.push_back({typeDecl, memberType});
370+
371+
continue;
372+
}
362373
}
363-
}
364374

365-
// Substitute the base into the member's type.
366-
if (Type memberType = substMemberTypeWithBase(dc->getParentModule(),
367-
typeDecl, type,
368-
/*isTypeReference=*/true)) {
369-
370-
// Similar to the associated type case, ignore typealiases containing
371-
// associated types when looking into a non-protocol.
372-
if (auto alias = dyn_cast<TypeAliasDecl>(typeDecl)) {
373-
auto parentProtocol = alias->getDeclContext()->
374-
getAsProtocolOrProtocolExtensionContext();
375-
if (parentProtocol && memberType->hasTypeParameter() &&
376-
!type->is<ArchetypeType>() && !type->isExistentialType()) {
375+
// If we're looking up an associated type of a concrete type,
376+
// record it later for conformance checking; we might find a more
377+
// direct typealias with the same name later.
378+
if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) {
379+
if (!type->is<ArchetypeType>()) {
380+
inferredAssociatedTypes.push_back(assocType);
377381
continue;
378382
}
379383
}
380384

381-
// If we haven't seen this type result yet, add it to the result set.
382-
if (types.insert(memberType->getCanonicalType()).second)
383-
result.Results.push_back({typeDecl, memberType});
385+
// We are looking up an associated type of an archetype, or a
386+
// protocol typealias or an archetype or concrete type.
387+
//
388+
// Proceed with the usual path below.
384389
}
390+
391+
// Substitute the base into the member's type.
392+
auto memberType = substMemberTypeWithBase(dc->getParentModule(),
393+
typeDecl, type,
394+
/*isTypeReference=*/true);
395+
396+
// FIXME: It is not clear why this substitution can fail, but the
397+
// standard library won't build without this check.
398+
if (!memberType)
399+
continue;
400+
401+
// If we haven't seen this type result yet, add it to the result set.
402+
if (types.insert(memberType->getCanonicalType()).second)
403+
result.Results.push_back({typeDecl, memberType});
385404
}
386405

387406
if (result.Results.empty()) {

0 commit comments

Comments
 (0)