Skip to content

Commit 40fff9c

Browse files
authored
Merge pull request swiftlang#40715 from DougGregor/named-opaque-result-types
Named opaque result types
2 parents 5a2f911 + ef7df1d commit 40fff9c

14 files changed

+289
-37
lines changed

include/swift/AST/Decl.h

Lines changed: 12 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

@@ -2779,6 +2781,16 @@ class OpaqueTypeDecl final :
27792781
return OpaqueInterfaceGenericSignature.getInnermostGenericParams();
27802782
}
27812783

2784+
/// Whether the generic parameters of this opaque type declaration were
2785+
/// explicit, i.e., for named opaque result types.
2786+
bool hasExplicitGenericParams() const;
2787+
2788+
/// When the generic parameters were explicit, returns the generic parameter
2789+
/// corresponding to the given ordinal.
2790+
///
2791+
/// Otherwise, returns \c nullptr.
2792+
GenericTypeParamDecl *getExplicitGenericParam(unsigned ordinal) const;
2793+
27822794
/// Retrieve the buffer containing the opaque return type
27832795
/// representations that correspond to the opaque generic parameters.
27842796
ArrayRef<OpaqueReturnTypeRepr *> getOpaqueReturnTypeReprs() const {

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4134,6 +4134,9 @@ ERROR(opaque_type_no_underlying_type_candidates,none,
41344134
ERROR(opaque_type_mismatched_underlying_type_candidates,none,
41354135
"function declares an opaque return type %0, but the return statements "
41364136
"in its body do not have matching underlying types", (TypeRepr *))
4137+
ERROR(opaque_type_mismatched_underlying_type_candidates_named,none,
4138+
"function declares an opaque return type %0, but the return statements "
4139+
"in its body do not have matching underlying types", (Identifier))
41374140
NOTE(opaque_type_underlying_type_candidate_here,none,
41384141
"return statement has underlying type %0", (Type))
41394142
ERROR(opaque_type_self_referential_underlying_type,none,

lib/AST/ASTMangler.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,17 @@ unsigned ASTMangler::appendBoundGenericArgs(DeclContext *dc,
15581558

15591559
// If we are generic at this level, emit all of the replacements at
15601560
// this level.
1561-
if (genericContext->isGeneric()) {
1561+
bool treatAsGeneric;
1562+
if (auto opaque = dyn_cast<OpaqueTypeDecl>(decl)) {
1563+
// For opaque type declarations, the generic parameters of the opaque
1564+
// type declaration are not part of the mangling, so check whether the
1565+
// naming declaration has generic parameters.
1566+
auto namedGenericContext = opaque->getNamingDecl()->getAsGenericContext();
1567+
treatAsGeneric = namedGenericContext && namedGenericContext->isGeneric();
1568+
} else {
1569+
treatAsGeneric = genericContext->isGeneric();
1570+
}
1571+
if (treatAsGeneric) {
15621572
auto genericParams = subs.getGenericSignature().getGenericParams();
15631573
unsigned depth = genericParams[currentGenericParamIdx]->getDepth();
15641574
auto replacements = subs.getReplacementTypes();

lib/AST/ASTPrinter.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4338,9 +4338,10 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
43384338
case PrintOptions::OpaqueReturnTypePrintingMode::Description:
43394339
return true;
43404340
case PrintOptions::OpaqueReturnTypePrintingMode::WithOpaqueKeyword:
4341-
return false;
4341+
return opaque->getDecl()->hasExplicitGenericParams();
43424342
case PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword:
4343-
return isSimpleUnderPrintOptions(opaque->getExistentialType());
4343+
return opaque->getDecl()->hasExplicitGenericParams() ||
4344+
isSimpleUnderPrintOptions(opaque->getExistentialType());
43444345
}
43454346
llvm_unreachable("bad opaque-return-type printing mode");
43464347
}
@@ -5410,11 +5411,28 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
54105411
}
54115412

54125413
void visitOpaqueTypeArchetypeType(OpaqueTypeArchetypeType *T) {
5414+
// Try to print a named opaque type.
5415+
auto printNamedOpaque = [&] {
5416+
if (auto genericParam =
5417+
T->getDecl()->getExplicitGenericParam(T->getOrdinal())) {
5418+
visit(genericParam->getDeclaredInterfaceType());
5419+
return true;
5420+
}
5421+
5422+
return false;
5423+
};
5424+
54135425
switch (Options.OpaqueReturnTypePrinting) {
54145426
case PrintOptions::OpaqueReturnTypePrintingMode::WithOpaqueKeyword:
5427+
if (printNamedOpaque())
5428+
return;
5429+
54155430
Printer.printKeyword("some", Options, /*Suffix=*/" ");
54165431
LLVM_FALLTHROUGH;
54175432
case PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword: {
5433+
if (printNamedOpaque())
5434+
return;
5435+
54185436
visit(T->getExistentialType());
54195437
return;
54205438
}

lib/AST/ASTScopeCreation.cpp

Lines changed: 40 additions & 6 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
@@ -849,6 +869,20 @@ TopLevelCodeScope::expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &
849869

850870
// Create child scopes for every declaration in a body.
851871

872+
namespace {
873+
/// Retrieve the opaque generic parameter list if present, otherwise the normal generic parameter list.
874+
template<typename T>
875+
GenericParamList *getPotentiallyOpaqueGenericParams(T *decl) {
876+
if (auto opaqueRepr = decl->getOpaqueResultTypeRepr()) {
877+
if (auto namedOpaque = dyn_cast<NamedOpaqueReturnTypeRepr>(opaqueRepr)) {
878+
return namedOpaque->getGenericParams();
879+
}
880+
}
881+
882+
return decl->getGenericParams();
883+
}
884+
}
885+
852886
void AbstractFunctionDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
853887
ScopeCreator &scopeCreator) {
854888
scopeCreator.addChildrenForKnownAttributes(decl, this);
@@ -860,7 +894,7 @@ void AbstractFunctionDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
860894

861895
if (!isa<AccessorDecl>(decl)) {
862896
leaf = scopeCreator.addNestedGenericParamScopesToTree(
863-
decl, decl->getGenericParams(), leaf);
897+
decl, getPotentiallyOpaqueGenericParams(decl), leaf);
864898

865899
auto *params = decl->getParameters();
866900
if (params->size() > 0) {
@@ -1008,7 +1042,7 @@ void SubscriptDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
10081042
ScopeCreator &scopeCreator) {
10091043
scopeCreator.addChildrenForKnownAttributes(decl, this);
10101044
auto *leaf = scopeCreator.addNestedGenericParamScopesToTree(
1011-
decl, decl->getGenericParams(), this);
1045+
decl, getPotentiallyOpaqueGenericParams(decl), this);
10121046
scopeCreator.constructExpandAndInsert<ParameterListScope>(
10131047
leaf, decl->getIndices(), decl->getAccessor(AccessorKind::Get));
10141048
scopeCreator.addChildrenForParsedAccessors(decl, leaf);

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/AST/Decl.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7829,6 +7829,19 @@ bool OpaqueTypeDecl::isOpaqueReturnTypeOfFunction(
78297829
return false;
78307830
}
78317831

7832+
bool OpaqueTypeDecl::hasExplicitGenericParams() const {
7833+
return getExplicitGenericParam(0) != nullptr;
7834+
}
7835+
7836+
GenericTypeParamDecl *OpaqueTypeDecl::getExplicitGenericParam(
7837+
unsigned ordinal) const {
7838+
if (ordinal >= getOpaqueGenericParams().size())
7839+
return nullptr;
7840+
7841+
auto genericParamType = getOpaqueGenericParams()[ordinal];
7842+
return genericParamType->getDecl();
7843+
}
7844+
78327845
unsigned OpaqueTypeDecl::getAnonymousOpaqueParamOrdinal(
78337846
OpaqueReturnTypeRepr *repr) const {
78347847
assert(NamingDeclAndHasOpaqueReturnTypeRepr.getInt() &&

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ Type ConstraintSystem::openOpaqueType(OpaqueTypeArchetypeType *opaque,
846846
if (knownReplacements != OpenedTypes.end()) {
847847
auto param = opaque->getInterfaceType()->castTo<GenericTypeParamType>();
848848
for (const auto &replacement : knownReplacements->second) {
849-
if (replacement.first == param)
849+
if (replacement.first->isEqual(param))
850850
return replacement.second;
851851
}
852852

lib/Sema/MiscDiagnostics.cpp

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2610,6 +2610,7 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
26102610
OpaqueTypeDecl *OpaqueDecl;
26112611
BraceStmt *Body;
26122612
SmallVector<Candidate, 4> Candidates;
2613+
SmallPtrSet<const void *, 4> KnownCandidates;
26132614

26142615
bool HasInvalidReturn = false;
26152616

@@ -2644,13 +2645,7 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
26442645
// Check whether all of the underlying type candidates match up.
26452646
// TODO [OPAQUE SUPPORT]: diagnose multiple opaque types
26462647
SubstitutionMap underlyingSubs = Candidates.front().second;
2647-
SubstitutionMap canonicalUnderlyingSubs = underlyingSubs.getCanonical();
2648-
bool mismatch =
2649-
std::any_of(Candidates.begin() + 1, Candidates.end(),
2650-
[&](Candidate &otherCandidate) {
2651-
return canonicalUnderlyingSubs != otherCandidate.second.getCanonical();
2652-
});
2653-
if (mismatch) {
2648+
if (Candidates.size() > 1) {
26542649
unsigned mismatchIndex = OpaqueDecl->getOpaqueGenericParams().size();
26552650
for (auto genericParam : OpaqueDecl->getOpaqueGenericParams()) {
26562651
unsigned index = genericParam->getIndex();
@@ -2669,12 +2664,21 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
26692664
break;
26702665
}
26712666
assert(mismatchIndex < OpaqueDecl->getOpaqueGenericParams().size());
2672-
TypeRepr *opaqueRepr =
2673-
OpaqueDecl->getOpaqueReturnTypeReprs()[mismatchIndex];
2674-
Implementation->diagnose(
2675-
diag::opaque_type_mismatched_underlying_type_candidates,
2676-
opaqueRepr)
2677-
.highlight(opaqueRepr->getSourceRange());
2667+
2668+
if (auto genericParam =
2669+
OpaqueDecl->getExplicitGenericParam(mismatchIndex)) {
2670+
Implementation->diagnose(
2671+
diag::opaque_type_mismatched_underlying_type_candidates_named,
2672+
genericParam->getName())
2673+
.highlight(genericParam->getLoc());
2674+
} else {
2675+
TypeRepr *opaqueRepr =
2676+
OpaqueDecl->getOpaqueReturnTypeReprs()[mismatchIndex];
2677+
Implementation->diagnose(
2678+
diag::opaque_type_mismatched_underlying_type_candidates,
2679+
opaqueRepr)
2680+
.highlight(opaqueRepr->getSourceRange());
2681+
}
26782682

26792683
for (auto candidate : Candidates) {
26802684
Ctx.Diags.diagnose(
@@ -2712,8 +2716,12 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
27122716

27132717
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
27142718
if (auto underlyingToOpaque = dyn_cast<UnderlyingToOpaqueExpr>(E)) {
2715-
Candidates.push_back(std::make_pair(underlyingToOpaque->getSubExpr(),
2716-
underlyingToOpaque->substitutions));
2719+
auto key =
2720+
underlyingToOpaque->substitutions.getCanonical().getOpaqueValue();
2721+
if (KnownCandidates.insert(key).second) {
2722+
Candidates.push_back(std::make_pair(underlyingToOpaque->getSubExpr(),
2723+
underlyingToOpaque->substitutions));
2724+
}
27172725
return {false, E};
27182726
}
27192727
return {true, E};

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

0 commit comments

Comments
 (0)