Skip to content

Unqualified lookup fixes, part 2 #19891

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
62 changes: 30 additions & 32 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -999,8 +999,6 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,

// Look in the generic parameters after checking our local declaration.
GenericParams = AFD->getGenericParams();
} else if (auto *SD = dyn_cast<SubscriptDecl>(DC)) {
GenericParams = SD->getGenericParams();
} else if (auto *ACE = dyn_cast<AbstractClosureExpr>(DC)) {
// Look for local variables; normally, the parser resolves these
// for us, but it can't do the right thing inside local types.
Expand Down Expand Up @@ -1042,12 +1040,14 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
continue;
} else {
assert(isa<TopLevelCodeDecl>(DC) || isa<Initializer>(DC) ||
isa<TypeAliasDecl>(DC));
isa<TypeAliasDecl>(DC) || isa<SubscriptDecl>(DC));
if (!isCascadingUse.hasValue())
isCascadingUse = DC->isCascadingContextForLookup(false);
}

// Check the generic parameters for something with the given name.
// If we're inside a function context, we've already moved to
// the parent DC, so we have to check the function's generic
// parameters first.
if (GenericParams) {
namelookup::FindLocalVal localVal(SM, Loc, Consumer);
localVal.checkGenericParams(GenericParams);
Expand All @@ -1056,6 +1056,30 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
return;
}

// Check the generic parameters of our context.
GenericParamList *dcGenericParams = nullptr;
if (auto nominal = dyn_cast<NominalTypeDecl>(DC))
dcGenericParams = nominal->getGenericParams();
else if (auto ext = dyn_cast<ExtensionDecl>(DC))
dcGenericParams = ext->getGenericParams();
else if (auto subscript = dyn_cast<SubscriptDecl>(DC))
dcGenericParams = subscript->getGenericParams();

while (dcGenericParams) {
namelookup::FindLocalVal localVal(SM, Loc, Consumer);
localVal.checkGenericParams(dcGenericParams);

if (shouldReturnBasedOnResults())
return;

// Extensions of nested types have multiple levels of
// generic parameters, so we have to visit them explicitly.
if (!isa<ExtensionDecl>(DC))
break;

dcGenericParams = dcGenericParams->getOuterParameters();
}

if (BaseDC && !lookupDecls.empty()) {
NLOptions options = baseNLOptions;
if (isCascadingUse.getValue())
Expand All @@ -1071,12 +1095,9 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
// Classify this declaration.
FoundAny = true;

// Types are local or metatype members.
// Types are formally members of the metatype.
if (auto TD = dyn_cast<TypeDecl>(Result)) {
if (isa<GenericTypeParamDecl>(TD))
Results.push_back(LookupResultEntry(Result));
else
Results.push_back(LookupResultEntry(MetaBaseDC, Result));
Results.push_back(LookupResultEntry(MetaBaseDC, Result));
continue;
}

Expand Down Expand Up @@ -1108,29 +1129,6 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
}
}

// Check the generic parameters if our context is a generic type or
// extension thereof.
GenericParamList *dcGenericParams = nullptr;
if (auto nominal = dyn_cast<NominalTypeDecl>(DC))
dcGenericParams = nominal->getGenericParams();
else if (auto ext = dyn_cast<ExtensionDecl>(DC))
dcGenericParams = ext->getGenericParams();
else if (auto subscript = dyn_cast<SubscriptDecl>(DC))
dcGenericParams = subscript->getGenericParams();

while (dcGenericParams) {
namelookup::FindLocalVal localVal(SM, Loc, Consumer);
localVal.checkGenericParams(dcGenericParams);

if (shouldReturnBasedOnResults())
return;

if (!isa<ExtensionDecl>(DC))
break;

dcGenericParams = dcGenericParams->getOuterParameters();
}

DC = DC->getParentForLookup();
}

Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2057,7 +2057,7 @@ static NominalTypeDecl *resolveSingleNominalTypeDecl(

TypeResolutionOptions options = TypeResolverContext::TypeAliasDecl;
options |= flags;
if (tc.validateType(typeLoc, TypeResolution::forContextual(DC), options))
if (tc.validateType(typeLoc, TypeResolution::forInterface(DC), options))
return nullptr;

return typeLoc.getType()->getAnyNominal();
Expand Down Expand Up @@ -3469,7 +3469,7 @@ static void validateTypealiasType(TypeChecker &tc, TypeAliasDecl *typeAlias) {
}

if (tc.validateType(typeAlias->getUnderlyingTypeLoc(),
TypeResolution::forContextual(typeAlias), options)) {
TypeResolution::forInterface(typeAlias), options)) {
typeAlias->setInvalid();
typeAlias->getUnderlyingTypeLoc().setInvalidType(tc.Context);
}
Expand Down
8 changes: 8 additions & 0 deletions test/NameBinding/name_lookup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -601,3 +601,11 @@ func test3() {
_ = b
}
}

// rdar://problem/22587551
class ShadowingGenericParameter<T> {
typealias T = Int
func foo (t : T) {}
}

_ = ShadowingGenericParameter<String>().foo(t: "hi")
3 changes: 2 additions & 1 deletion test/Sema/circular_decl_checking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ class X {

// <rdar://problem/17144076> recursive typealias causes a segfault in the type checker
struct SomeStruct<A> {
typealias A = A // expected-error {{type alias 'A' references itself}}
typealias A = A // this is OK now -- the underlying type is the generic parameter 'A'
typealias B = B // expected-error {{type alias 'B' references itself}}
// expected-note@-1 {{type declared here}}
}

Expand Down
47 changes: 47 additions & 0 deletions test/api-digester/Outputs/stability-stdlib-source.swift.expected
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,53 @@
/* Renamed Decls */

/* Type Changes */
Func AnyBidirectionalCollection.formIndex(_:offsetBy:) has parameter 0 changing from Default to InOut
Func AnyBidirectionalCollection.formIndex(_:offsetBy:limitedBy:) has parameter 0 changing from Default to InOut
Func AnyBidirectionalCollection.formIndex(after:) has parameter 0 changing from Default to InOut
Func AnyBidirectionalCollection.formIndex(before:) has parameter 0 changing from Default to InOut
Func AnyCollection.formIndex(_:offsetBy:) has parameter 0 changing from Default to InOut
Func AnyCollection.formIndex(_:offsetBy:limitedBy:) has parameter 0 changing from Default to InOut
Func AnyCollection.formIndex(after:) has parameter 0 changing from Default to InOut
Func AnyRandomAccessCollection.formIndex(_:offsetBy:) has parameter 0 changing from Default to InOut
Func AnyRandomAccessCollection.formIndex(_:offsetBy:limitedBy:) has parameter 0 changing from Default to InOut
Func AnyRandomAccessCollection.formIndex(after:) has parameter 0 changing from Default to InOut
Func AnyRandomAccessCollection.formIndex(before:) has parameter 0 changing from Default to InOut
Func Array.append(_:) has parameter 0 changing from Default to Owned
Func Array.append(_:) has parameter 0 type change from Array<Element>.Element to Element
Func Array.insert(_:at:) has parameter 0 changing from Default to Owned
Func Array.insert(_:at:) has parameter 0 type change from Array<Element>.Element to Element
Func ArraySlice.append(_:) has parameter 0 changing from Default to Owned
Func ArraySlice.append(_:) has parameter 0 type change from ArraySlice<Element>.Element to Element
Func ArraySlice.insert(_:at:) has parameter 0 changing from Default to Owned
Func ArraySlice.insert(_:at:) has parameter 0 type change from ArraySlice<Element>.Element to Element
Func ContiguousArray.append(_:) has parameter 0 changing from Default to Owned
Func ContiguousArray.append(_:) has parameter 0 type change from ContiguousArray<Element>.Element to Element
Func ContiguousArray.insert(_:at:) has parameter 0 changing from Default to Owned
Func ContiguousArray.insert(_:at:) has parameter 0 type change from ContiguousArray<Element>.Element to Element
Func DefaultIndices.formIndex(after:) has parameter 0 changing from Default to InOut
Func DefaultIndices.formIndex(before:) has parameter 0 changing from Default to InOut
Func Dictionary.updateValue(_:forKey:) has parameter 0 changing from Default to Owned
Func Dictionary.updateValue(_:forKey:) has parameter 0 type change from Dictionary<Key, Value>.Value to Value
Func LazyFilterCollection.formIndex(_:offsetBy:) has parameter 0 changing from Default to InOut
Func LazyFilterCollection.formIndex(_:offsetBy:limitedBy:) has parameter 0 changing from Default to InOut
Func LazyFilterCollection.formIndex(after:) has parameter 0 changing from Default to InOut
Func LazyFilterCollection.formIndex(before:) has parameter 0 changing from Default to InOut
Func LazyMapCollection.formIndex(after:) has parameter 0 changing from Default to InOut
Func LazyMapCollection.formIndex(before:) has parameter 0 changing from Default to InOut
Func Set.insert(_:) has parameter 0 changing from Default to Owned
Func Set.insert(_:) has parameter 0 type change from Set<Element>.Element to Element
Func Set.update(with:) has parameter 0 changing from Default to Owned
Func Set.update(with:) has parameter 0 type change from Set<Element>.Element to Element
Func Slice.formIndex(after:) has parameter 0 changing from Default to InOut
Func Slice.formIndex(before:) has parameter 0 changing from Default to InOut
Func String.UTF16View.Indices.formIndex(after:) has parameter 0 changing from Default to InOut
Func String.UTF16View.Indices.formIndex(before:) has parameter 0 changing from Default to InOut
Func Substring.UTF16View.formIndex(after:) has parameter 0 changing from Default to InOut
Func Substring.UTF16View.formIndex(before:) has parameter 0 changing from Default to InOut
Func Substring.UTF8View.formIndex(after:) has parameter 0 changing from Default to InOut
Func Substring.UTF8View.formIndex(before:) has parameter 0 changing from Default to InOut
Func Substring.UnicodeScalarView.formIndex(after:) has parameter 0 changing from Default to InOut
Func Substring.UnicodeScalarView.formIndex(before:) has parameter 0 changing from Default to InOut

/* Decl Attribute changes */

Expand Down
19 changes: 19 additions & 0 deletions test/decl/protocol/req/associated_type_inference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -508,3 +508,22 @@ protocol P20 {
struct S19 : P20 { // expected-error{{type 'S19' does not conform to protocol 'P20'}}
typealias TT = Int?
}

// rdar://problem/44777661
struct S30<T> where T : P30 {}

protocol P30 {
static func bar()
}

protocol P31 {
associatedtype T : P30
}

extension S30 : P31 where T : P31 {}

extension S30 {
func foo() {
T.bar()
}
}
7 changes: 6 additions & 1 deletion test/decl/typealias/protocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,18 @@ protocol P3 {

// Test for not crashing on recursive aliases
protocol Circular {
typealias Y = Self.Y // expected-error {{type alias 'Y' is not a member type of 'Self'}}
typealias Y = Self.Y // expected-error {{'Y' is not a member type of 'Self'}}
// expected-note@-1 {{did you mean 'Y'?}}

typealias Y2 = Y2 // expected-error {{type alias 'Y2' references itself}}
// expected-note@-1 {{type declared here}}
// expected-note@-2 {{did you mean 'Y2'?}}

typealias Y3 = Y4 // expected-note {{type declared here}}
// expected-note@-1 {{did you mean 'Y3'?}}

typealias Y4 = Y3 // expected-error {{type alias 'Y3' references itself}}
// expected-note@-1 {{did you mean 'Y4'?}}
}

// Qualified and unqualified references to protocol typealiases from concrete type
Expand Down
39 changes: 26 additions & 13 deletions tools/swift-api-digester/ModuleAnalyzerNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,13 +654,29 @@ static bool hasSameContents(ArrayRef<StringRef> Left,
return LeftMinusRight.empty() && RightMinusLeft.empty();
}

bool static isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R) {
static bool hasSameParameterFlags(const SDKNodeType *Left, const SDKNodeType *Right) {
if (Left->hasDefaultArgument() != Right->hasDefaultArgument())
return false;
if (Left->getParamValueOwnership() != Right->getParamValueOwnership())
return false;

return true;
}

static bool isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R) {
auto *LeftAlias = dyn_cast<SDKNodeTypeAlias>(&L);
auto *RightAlias = dyn_cast<SDKNodeTypeAlias>(&R);
if (LeftAlias || RightAlias) {
auto Left = L.getAs<SDKNodeType>();
auto Right = R.getAs<SDKNodeType>();

// First compare the parameter attributes.
if (!hasSameParameterFlags(Left, Right))
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extract these two conditions along with "if (Left->hasAttributeChange(*Right)) return false;" to a static helper function so this type alias logic can be shared with other types? Otherwise LGTM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks you!


// Comparing the underlying types if any of the inputs are alias.
const SDKNode *Left = LeftAlias ? LeftAlias->getUnderlyingType() : &L;
const SDKNode *Right = RightAlias ? RightAlias->getUnderlyingType() : &R;
Left = LeftAlias ? LeftAlias->getUnderlyingType() : Left;
Right = RightAlias ? RightAlias->getUnderlyingType() : Right;
return *Left == *Right;
}

Expand All @@ -676,9 +692,7 @@ bool static isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R)
auto Right = R.getAs<SDKNodeType>();
if (Left->hasAttributeChange(*Right))
return false;
if (Left->hasDefaultArgument() != Right->hasDefaultArgument())
return false;
if (Left->getParamValueOwnership() != Right->getParamValueOwnership())
if (!hasSameParameterFlags(Left, Right))
return false;
if (Left->getPrintedName() == Right->getPrintedName())
return true;
Expand Down Expand Up @@ -740,8 +754,6 @@ bool static isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R)
if (auto *Right = dyn_cast<SDKNodeDeclSubscript>(&R)) {
if (Left->hasSetter() != Right->hasSetter())
return false;
if (Left->hasStorage() != Right->hasStorage())
return false;
}
}
LLVM_FALLTHROUGH;
Expand Down Expand Up @@ -776,7 +788,7 @@ bool static isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R)
}
}

llvm_unreachable("Unhanlded SDKNodeKind in switch.");
llvm_unreachable("Unhandled SDKNodeKind in switch.");
}

bool SDKContext::isEqual(const SDKNode &Left, const SDKNode &Right) {
Expand Down Expand Up @@ -1166,16 +1178,15 @@ SwiftDeclCollector::constructTypeNode(Type T, TypeInitInfo Info) {
if (Ctx.checkingABI()) {
T = T->getCanonicalType();
}
SDKNode* Root = SDKNodeInitInfo(Ctx, T, Info).createSDKNode(SDKNodeKind::TypeNominal);

if (auto NAT = dyn_cast<NameAliasType>(T.getPointer())) {
SDKNode* Root = SDKNodeInitInfo(Ctx, T).createSDKNode(SDKNodeKind::TypeAlias);
Root->addChild(constructTypeNode(NAT->getCanonicalType()));
SDKNode* Root = SDKNodeInitInfo(Ctx, T, Info).createSDKNode(SDKNodeKind::TypeAlias);
Root->addChild(constructTypeNode(NAT->getSinglyDesugaredType()));
return Root;
}

if (auto Fun = T->getAs<AnyFunctionType>()) {
SDKNode* Root = SDKNodeInitInfo(Ctx, T).createSDKNode(SDKNodeKind::TypeFunc);
SDKNode* Root = SDKNodeInitInfo(Ctx, T, Info).createSDKNode(SDKNodeKind::TypeFunc);

// Still, return type first
Root->addChild(constructTypeNode(Fun->getResult()));
Expand All @@ -1187,6 +1198,8 @@ SwiftDeclCollector::constructTypeNode(Type T, TypeInitInfo Info) {
return Root;
}

SDKNode* Root = SDKNodeInitInfo(Ctx, T, Info).createSDKNode(SDKNodeKind::TypeNominal);

// Keep paren type as a stand-alone level.
if (auto *PT = dyn_cast<ParenType>(T.getPointer())) {
Root->addChild(constructTypeNode(PT->getSinglyDesugaredType()));
Expand Down
2 changes: 1 addition & 1 deletion tools/swift-api-digester/swift-api-digester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ class InterfaceTypeChangeDetector {
if (IsVisitingLeft &&
Node->getPrintedName() != Counter->getPrintedName() &&
(Node->getName() != Counter->getName() ||
Node->getChildrenCount() != Counter->getChildrenCount())) {
Node->getChildrenCount() != Counter->getChildrenCount())) {
Node->annotate(NodeAnnotation::TypeRewritten);
Node->annotate(NodeAnnotation::TypeRewrittenLeft, Node->getPrintedName());
Node->annotate(NodeAnnotation::TypeRewrittenRight,
Expand Down