Skip to content

Commit 55067ba

Browse files
committed
Support named opaque result types for properties.
Add lookup scopes for the generic parameters of a named opaque result type and clean up the code that finds the opaque substitutions.
1 parent ed79bab commit 55067ba

File tree

6 files changed

+76
-7
lines changed

6 files changed

+76
-7
lines changed

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ namespace swift {
106106

107107
namespace ast_scope {
108108
class AbstractPatternEntryScope;
109+
class GenericParamScope;
109110
class PatternEntryDeclScope;
110111
class PatternEntryInitializerScope;
111112
} // namespace ast_scope
@@ -1565,6 +1566,7 @@ class PatternBindingEntry {
15651566
friend class PatternBindingInitializer;
15661567
friend class PatternBindingDecl;
15671568
friend class ast_scope::AbstractPatternEntryScope;
1569+
friend class ast_scope::GenericParamScope;
15681570
friend class ast_scope::PatternEntryDeclScope;
15691571
friend class ast_scope::PatternEntryInitializerScope;
15701572

lib/AST/ASTScopeCreation.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,26 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint(
708708
// Initializers come before VarDecls, e.g. PCMacro/didSet.swift 19
709709
auto patternEntry = getPatternEntry();
710710

711+
// If the pattern type is for a named opaque result type, introduce the
712+
// generic type parameters based on the first variable we find.
713+
ASTScopeImpl *leaf = this;
714+
auto pattern = patternEntry.getPattern();
715+
if (auto typedPattern = dyn_cast<TypedPattern>(pattern)) {
716+
if (auto namedOpaque =
717+
dyn_cast_or_null<NamedOpaqueReturnTypeRepr>(
718+
typedPattern->getTypeRepr())) {
719+
bool addedOpaqueResultTypeScope = false;
720+
pattern->forEachVariable([&](VarDecl *var) {
721+
if (addedOpaqueResultTypeScope)
722+
return;
723+
724+
leaf = scopeCreator.addNestedGenericParamScopesToTree(
725+
var, namedOpaque->getGenericParams(), leaf);
726+
addedOpaqueResultTypeScope = true;
727+
});
728+
}
729+
}
730+
711731
// Create a child for the initializer, if present.
712732
// Cannot trust the source range given in the ASTScopeImpl for the end of the
713733
// initializer (because of InterpolatedLiteralStrings and EditorPlaceHolders),
@@ -724,7 +744,7 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint(
724744
"Original inits are always after the '='");
725745
scopeCreator
726746
.constructExpandAndInsert<PatternEntryInitializerScope>(
727-
this, decl, patternEntryIndex);
747+
leaf, decl, patternEntryIndex);
728748
}
729749

730750
// If this pattern binding entry was created by the debugger, it will always
@@ -741,12 +761,12 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint(
741761
"inits are always after the '='");
742762
scopeCreator
743763
.constructExpandAndInsert<PatternEntryInitializerScope>(
744-
this, decl, patternEntryIndex);
764+
leaf, decl, patternEntryIndex);
745765
}
746766

747767
// Add accessors for the variables in this pattern.
748-
patternEntry.getPattern()->forEachVariable([&](VarDecl *var) {
749-
scopeCreator.addChildrenForParsedAccessors(var, this);
768+
pattern->forEachVariable([&](VarDecl *var) {
769+
scopeCreator.addChildrenForParsedAccessors(var, leaf);
750770
});
751771

752772
// In local context, the PatternEntryDeclScope becomes the insertion point, so

lib/AST/ASTScopeLookup.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,14 @@ bool GenericTypeOrExtensionScope::areMembersVisibleFromWhereClause() const {
266266
NullablePtr<const ASTScopeImpl>
267267
PatternEntryInitializerScope::getLookupParent() const {
268268
auto parent = getParent().get();
269+
270+
// Skip generic parameter scopes, which occur here due to named opaque
271+
// result types.
272+
// FIXME: Proper isa/dyn_cast support would be better than a string
273+
// comparison here.
274+
while (parent->getClassName() == "GenericParamScope")
275+
parent = parent->getLookupParent().get();
276+
269277
ASTScopeAssert(parent->getClassName() == "PatternEntryDeclScope",
270278
"PatternEntryInitializerScope in unexpected place");
271279

lib/AST/ASTScopeSourceRange.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ SourceRange GenericParamScope::getSourceRangeOfThisASTNode(
161161
return SourceRange(getLocAfterExtendedNominal(ext), ext->getEndLoc());
162162
}
163163

164+
// For a variable, the generic parameter is visible throughout the pattern
165+
// binding entry.
166+
if (auto var = dyn_cast<VarDecl>(holder)) {
167+
if (auto patternBinding = var->getParentPatternBinding()) {
168+
unsigned index = patternBinding->getPatternEntryIndexForVarDecl(var);
169+
return patternBinding->getPatternList()[index].getSourceRange();
170+
}
171+
}
172+
164173
// For all other declarations, generic parameters are visible everywhere.
165174
return holder->getSourceRange();
166175
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,14 +541,23 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
541541
// Bind a property with an opaque return type to the underlying type
542542
// given by the initializer.
543543
if (auto var = pattern->getSingleVar()) {
544+
SubstitutionMap substitutions;
544545
if (auto opaque = var->getOpaqueResultTypeDecl()) {
545546
init->forEachChildExpr([&](Expr *expr) -> Expr * {
546547
if (auto coercionExpr = dyn_cast<UnderlyingToOpaqueExpr>(expr)) {
547-
opaque->setUnderlyingTypeSubstitutions(
548-
coercionExpr->substitutions.mapReplacementTypesOutOfContext());
548+
auto newSubstitutions =
549+
coercionExpr->substitutions.mapReplacementTypesOutOfContext();
550+
if (substitutions.empty()) {
551+
substitutions = newSubstitutions;
552+
} else {
553+
assert(substitutions.getCanonical() ==
554+
newSubstitutions.getCanonical());
555+
}
549556
}
550557
return expr;
551558
});
559+
560+
opaque->setUnderlyingTypeSubstitutions(substitutions);
552561
}
553562
}
554563

test/type/opaque_return_named.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,14 @@ func f4(cond: Bool) -> <T: P1, U where U: Q1> (T, U) {
100100
func f5(cond: Bool) -> <T: P1, U where U: Q1> (T, U) { }
101101
// expected-error@-1{{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
102102

103-
struct Generic<T: P1 & Equatable> {
103+
protocol DefaultInitializable {
104+
init()
105+
}
106+
107+
extension String: DefaultInitializable { }
108+
extension Int: DefaultInitializable { }
109+
110+
struct Generic<T: P1 & Equatable & DefaultInitializable> {
104111
var value: T
105112

106113
func f() -> <U: Q1, V: P1 where U: Equatable, V: Equatable> (U, V) {
@@ -110,6 +117,20 @@ struct Generic<T: P1 & Equatable> {
110117
subscript(index: Int) -> <U: Q1, V: P1 where U: Equatable, V: Equatable> (U, V) {
111118
return ("hello", value)
112119
}
120+
121+
var property: <U: Q1, V: P1 where U: Equatable, V: Equatable> (U, V) {
122+
return ("hello", value)
123+
}
124+
125+
var property2: <U: Q1, V: P1 where U: Equatable, V: Equatable> (U, V) =
126+
("hello", T())
127+
128+
var property3: <U: Q1, V: P1 where U: Equatable, V: Equatable> (U, V) =
129+
("hello", T()) {
130+
didSet {
131+
print("here")
132+
}
133+
}
113134
}
114135

115136
func testGeneric(i: Int, gs: Generic<String>, gi: Generic<Int>) {

0 commit comments

Comments
 (0)