Skip to content

[NameLookup] Collect implicit opaque GenericParams #64037

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
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
3 changes: 2 additions & 1 deletion include/swift/AST/NameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class ASTScopeImpl;
/// Walk the type representation recursively, collecting any
/// \c OpaqueReturnTypeRepr, \c CompositionTypeRepr or \c DeclRefTypeRepr
/// nodes.
CollectedOpaqueReprs collectOpaqueReturnTypeReprs(TypeRepr *, ASTContext &ctx, DeclContext *dc);
CollectedOpaqueReprs collectOpaqueTypeReprs(TypeRepr *, ASTContext &ctx,
DeclContext *dc);

/// LookupResultEntry - One result of unqualified lookup.
struct LookupResultEntry {
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr
}

/// Is this type representation a protocol?
bool isProtocol(DeclContext *dc);
bool isProtocolOrProtocolComposition(DeclContext *dc);

/// Is this type representation known to be invalid?
bool isInvalid() const { return Bits.TypeRepr.Invalid; }
Expand Down
5 changes: 2 additions & 3 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3301,9 +3301,8 @@ TypeRepr *ValueDecl::getOpaqueResultTypeRepr() const {
if (returnRepr && returnRepr->hasOpaque()) {
return returnRepr;
} else if (returnRepr && ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {
auto opaqueReprs = collectOpaqueReturnTypeReprs(returnRepr,
getASTContext(),
getDeclContext());
auto opaqueReprs =
collectOpaqueTypeReprs(returnRepr, getASTContext(), getDeclContext());
return opaqueReprs.empty() ? nullptr : returnRepr;
} else {
return nullptr;
Expand Down
31 changes: 17 additions & 14 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2924,7 +2924,7 @@ static bool declsAreAssociatedTypes(ArrayRef<TypeDecl *> decls) {
/// Verify there is at least one protocols in the set of declarations.
static bool declsAreProtocols(ArrayRef<TypeDecl *> decls) {
if (decls.empty())
return false;
return false; // Below, check outer type repr is a protocol, if not bail early
return llvm::any_of(decls, [&](const TypeDecl *decl) {
if (auto *alias = dyn_cast<TypeAliasDecl>(decl)) {
auto ty = alias->getUnderlyingType();
Expand All @@ -2933,14 +2933,12 @@ static bool declsAreProtocols(ArrayRef<TypeDecl *> decls) {
return false;
}
return isa<ProtocolDecl>(decl);
});;;
});
}

bool TypeRepr::isProtocol(DeclContext *dc){
bool TypeRepr::isProtocolOrProtocolComposition(DeclContext *dc){
auto &ctx = dc->getASTContext();
return findIf([&ctx, dc](TypeRepr *ty) {
return declsAreProtocols(directReferencesForTypeRepr(ctx.evaluator, ctx, ty, dc));
});
return declsAreProtocols(directReferencesForTypeRepr(ctx.evaluator, ctx, this, dc));
}

static GenericParamList *
Expand All @@ -2962,7 +2960,8 @@ createExtensionGenericParams(ASTContext &ctx,
return toParams;
}

CollectedOpaqueReprs swift::collectOpaqueReturnTypeReprs(TypeRepr *r, ASTContext &ctx, DeclContext *d) {
CollectedOpaqueReprs swift::collectOpaqueTypeReprs(TypeRepr *r, ASTContext &ctx,
DeclContext *d) {
class Walker : public ASTWalker {
CollectedOpaqueReprs &Reprs;
ASTContext &Ctx;
Expand Down Expand Up @@ -2993,15 +2992,19 @@ CollectedOpaqueReprs swift::collectOpaqueReturnTypeReprs(TypeRepr *r, ASTContext

if (auto existential = dyn_cast<ExistentialTypeRepr>(repr)) {
return Action::SkipChildren();
} else if (auto compositionRepr = dyn_cast<CompositionTypeRepr>(repr)) {
if (!compositionRepr->isTypeReprAny())
Reprs.push_back(compositionRepr);
} else if (auto composition = dyn_cast<CompositionTypeRepr>(repr)) {
if (!composition->isTypeReprAny())
Reprs.push_back(composition);
return Action::SkipChildren();
} else if (auto generic = dyn_cast<GenericIdentTypeRepr>(repr)) {
if (generic->isProtocolOrProtocolComposition(dc)){
Reprs.push_back(generic);
return Action::SkipChildren();
}
return Action::Continue();
} else if (auto declRefTR = dyn_cast<DeclRefTypeRepr>(repr)) {
if (declRefTR->isProtocol(dc))
Reprs.push_back(declRefTR);
} else if (auto declRef = dyn_cast<DeclRefTypeRepr>(repr)) {
if (declRef->isProtocolOrProtocolComposition(dc))
Reprs.push_back(declRef);
}
return Action::Continue();
}
Expand Down Expand Up @@ -3043,7 +3046,7 @@ createOpaqueParameterGenericParams(GenericContext *genericContext, GenericParamL

// Plain protocols should imply 'some' with experimetal feature
CollectedOpaqueReprs typeReprs;
typeReprs = collectOpaqueReturnTypeReprs(typeRepr, ctx, dc);
typeReprs = collectOpaqueTypeReprs(typeRepr, ctx, dc);

for (auto repr : typeReprs) {

Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,
return nullptr;
}
} else {
opaqueReprs = collectOpaqueReturnTypeReprs(repr, ctx, dc);
opaqueReprs = collectOpaqueTypeReprs(repr, ctx, dc);

if (opaqueReprs.empty()) {
return nullptr;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ validateTypedPattern(TypedPattern *TP, DeclContext *dc,
auto *Repr = TP->getTypeRepr();
if (Repr && (Repr->hasOpaque() ||
(Context.LangOpts.hasFeature(Feature::ImplicitSome) &&
!collectOpaqueReturnTypeReprs(Repr, Context, dc).empty()))) {
!collectOpaqueTypeReprs(Repr, Context, dc).empty()))) {
auto named = dyn_cast<NamedPattern>(
TP->getSubPattern()->getSemanticsProvidingPattern());
if (!named) {
Expand Down
8 changes: 3 additions & 5 deletions test/type/implicit_some/opaque_parameters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,9 @@ func consumingA(fn: (P) -> Void) { } // expected-error{{'some' cannot appear in
func consumingB(fn: FnType<P>) { } // expected-error{{'some' cannot appear in parameter position in parameter type '(P) -> Void'}}


// TO-DO Handle plain generic opaque parameters
func takePrimaryCollections(
_ strings:some Collection<String>,
_ ints : some Collection<Int>
_ strings: Collection<String>,
_ ints : Collection<Int>
) {
for s in strings {
let _: String = s
Expand All @@ -75,9 +74,8 @@ func takePrimaryCollections(
let _: Int = i
}
}
// TO-DO Handle plain generic opaque parameters
func takeMatchedPrimaryCollections<T: Equatable>(
_ first: some Collection<T>, _ second: some Collection<T>
_ first: Collection<T>, _ second: Collection<T>
) -> Bool {
first.elementsEqual(second)
}
Expand Down
11 changes: 11 additions & 0 deletions test/type/implicit_some/opaque_return.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,14 @@ enum E {
protocol Q {
func f() -> Int
}

func findBiggerCollection<T : Numeric>( _ first: Collection<T>, _ second: Collection<T>) -> Collection<T> {
// expected-error@-1 {{function declares an opaque return type 'Collection<T>', but the return statements in its body do not have matching underlying types}}
if (first.count > second.count) { return first } //expected-note {{return statement has underlying type 'Collection<T>'}}
return second //expected-note {{return statement has underlying type 'Collection<T>'}}
}

func createCollection() -> Collection<Int> {
let a = [9,2,0]
return a
}