Skip to content

Commit 0ca2cc9

Browse files
authored
Merge pull request #60044 from slavapestov/fix-two-opaque-return-type-bugs
Fix two opaque return type bugs
2 parents fadee9c + 78e9af7 commit 0ca2cc9

File tree

6 files changed

+144
-39
lines changed

6 files changed

+144
-39
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4215,6 +4215,9 @@ NOTE(opaque_type_underlying_type_candidate_here,none,
42154215
ERROR(opaque_type_self_referential_underlying_type,none,
42164216
"function opaque return type was inferred as %0, which defines the "
42174217
"opaque type in terms of itself", (Type))
4218+
ERROR(opaque_type_cannot_contain_dynamic_self,none,
4219+
"function with opaque return type cannot return "
4220+
"the covariant 'Self' type of a class", ())
42184221
ERROR(opaque_type_var_no_init,none,
42194222
"property declares an opaque return type, but has no initializer "
42204223
"expression from which to infer an underlying type", ())

lib/SILGen/SILGenExpr.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,11 +2129,9 @@ RValue RValueEmitter::visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E,
21292129
if (value.getType() == opaqueTL.getLoweredType())
21302130
return RValue(SGF, E, value);
21312131

2132-
auto cast = SGF.B.createUncheckedReinterpretCast(E, value.forward(SGF),
2133-
opaqueTL.getLoweredType());
2134-
value = SGF.emitManagedRValueWithCleanup(cast);
2135-
2136-
return RValue(SGF, E, value);
2132+
auto cast = SGF.B.createUncheckedBitCast(E, value,
2133+
opaqueTL.getLoweredType());
2134+
return RValue(SGF, E, cast);
21372135
}
21382136

21392137
VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,

lib/Sema/CSApply.cpp

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6875,6 +6875,60 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
68756875
}
68766876
}
68776877

6878+
// Use an opaque type to abstract a value of the underlying concrete type.
6879+
// The full check here would be that `toType` and `fromType` are structurally
6880+
// equal except in any position where `toType` has an opaque archetype. The
6881+
// below is just an approximate check since the above would be expensive to
6882+
// verify and still relies on the type checker ensuing `fromType` is
6883+
// compatible with any opaque archetypes.
6884+
if (toType->hasOpaqueArchetype() &&
6885+
cs.getConstraintLocator(locator)->isForContextualType()) {
6886+
// Find the opaque type declaration. We need its generic signature.
6887+
OpaqueTypeDecl *opaqueDecl = nullptr;
6888+
bool found = toType.findIf([&](Type type) {
6889+
if (auto opaqueType = type->getAs<OpaqueTypeArchetypeType>()) {
6890+
opaqueDecl = opaqueType->getDecl();
6891+
return true;
6892+
}
6893+
6894+
return false;
6895+
});
6896+
(void)found;
6897+
assert(found && "No opaque type archetype?");
6898+
6899+
// Compute the substitutions for the opaque type declaration.
6900+
auto opaqueLocator = solution.getConstraintSystem().getOpenOpaqueLocator(
6901+
locator, opaqueDecl);
6902+
SubstitutionMap substitutions = solution.computeSubstitutions(
6903+
opaqueDecl->getOpaqueInterfaceGenericSignature(), opaqueLocator);
6904+
6905+
// If we don't have substitutions, this is an opaque archetype from
6906+
// another declaration being manipulated, and not an erasure of a
6907+
// concrete type to an opaque type inside its defining declaration.
6908+
if (!substitutions.empty()) {
6909+
// Compute the underlying type by replacing all opaque archetypes with
6910+
// the fixed type of their opened type.
6911+
auto underlyingType = toType.subst(
6912+
[&](SubstitutableType *type) -> Type {
6913+
if (auto *opaqueType = type->getAs<OpaqueTypeArchetypeType>()) {
6914+
if (opaqueType->getDecl() == opaqueDecl) {
6915+
return opaqueType->getInterfaceType().subst(substitutions);
6916+
}
6917+
}
6918+
return type;
6919+
},
6920+
LookUpConformanceInModule(cs.DC->getParentModule()),
6921+
SubstFlags::SubstituteOpaqueArchetypes);
6922+
6923+
// Coerce the result expression to the underlying type.
6924+
// FIXME: Wrong locator?
6925+
auto *subExpr = coerceToType(expr, underlyingType, locator);
6926+
6927+
return cs.cacheType(
6928+
new (ctx) UnderlyingToOpaqueExpr(subExpr, toType, substitutions));
6929+
}
6930+
}
6931+
68786932
// Handle "from specific" coercions before "catch all" coercions.
68796933
auto desugaredFromType = fromType->getDesugaredType();
68806934
switch (desugaredFromType->getKind()) {
@@ -7260,36 +7314,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
72607314
if (fromType->hasUnresolvedType() || toType->hasUnresolvedType())
72617315
return cs.cacheType(new (ctx) UnresolvedTypeConversionExpr(expr, toType));
72627316

7263-
// Use an opaque type to abstract a value of the underlying concrete type.
7264-
// The full check here would be that `toType` and `fromType` are structurally
7265-
// equal except in any position where `toType` has an opaque archetype. The
7266-
// below is just an approximate check since the above would be expensive to
7267-
// verify and still relies on the type checker ensuing `fromType` is
7268-
// compatible with any opaque archetypes.
7269-
if (toType->hasOpaqueArchetype()) {
7270-
// Find the opaque type declaration. We need its generic signature.
7271-
OpaqueTypeDecl *opaqueDecl = nullptr;
7272-
bool found = toType.findIf([&](Type type) {
7273-
if (auto opaqueType = type->getAs<OpaqueTypeArchetypeType>()) {
7274-
opaqueDecl = opaqueType->getDecl();
7275-
return true;
7276-
}
7277-
7278-
return false;
7279-
});
7280-
(void)found;
7281-
assert(found && "No opaque type archetype?");
7282-
7283-
// Compute the substitutions for the opaque type declaration.
7284-
auto opaqueLocator = solution.getConstraintSystem().getOpenOpaqueLocator(
7285-
locator, opaqueDecl);
7286-
SubstitutionMap substitutions = solution.computeSubstitutions(
7287-
opaqueDecl->getOpaqueInterfaceGenericSignature(), opaqueLocator);
7288-
assert(!substitutions.empty() && "Missing substitutions for opaque type");
7289-
return cs.cacheType(
7290-
new (ctx) UnderlyingToOpaqueExpr(expr, toType, substitutions));
7291-
}
7292-
72937317
llvm_unreachable("Unhandled coercion");
72947318
}
72957319

lib/Sema/MiscDiagnostics.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2846,20 +2846,26 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
28462846

28472847
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
28482848
if (auto underlyingToOpaque = dyn_cast<UnderlyingToOpaqueExpr>(E)) {
2849-
auto key =
2850-
underlyingToOpaque->substitutions.getCanonical().getOpaqueValue();
2849+
auto subMap = underlyingToOpaque->substitutions;
28512850

2851+
auto key = subMap.getCanonical().getOpaqueValue();
28522852
auto isUnique = UniqueSignatures.insert(key).second;
28532853

28542854
auto candidate =
2855-
std::make_tuple(underlyingToOpaque->getSubExpr(),
2856-
underlyingToOpaque->substitutions, isUnique);
2855+
std::make_tuple(underlyingToOpaque->getSubExpr(), subMap, isUnique);
28572856

28582857
if (isSelfReferencing(candidate)) {
28592858
HasInvalidReturn = true;
28602859
return {false, nullptr};
28612860
}
28622861

2862+
if (subMap.hasDynamicSelf()) {
2863+
Ctx.Diags.diagnose(E->getLoc(),
2864+
diag::opaque_type_cannot_contain_dynamic_self);
2865+
HasInvalidReturn = true;
2866+
return {false, nullptr};
2867+
}
2868+
28632869
Candidates.push_back({CurrentAvailability, candidate});
28642870
return {false, E};
28652871
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %target-swift-emit-silgen -disable-availability-checking %s
2+
3+
public protocol P {}
4+
5+
extension P {
6+
// This will only typecheck and SILGen if we emit the UnderlyingToOpaqueExpr
7+
// instead of a MetatypeConversionExpr
8+
public func f1() -> (some P).Type {
9+
return Self.self
10+
}
11+
12+
// This will only typecheck and SILGen if we emit the UnderlyingToOpaqueExpr
13+
// instead of a FunctionConversionExpr
14+
public func f2() -> () -> (some P) {
15+
let fn = { self }
16+
return fn
17+
}
18+
19+
// FIXME: This still doesn't work because the '() -> (some P)' propagates
20+
// backwards into the closure literal's return type
21+
/* public func f3() -> () -> (some P) {
22+
return { self }
23+
} */
24+
25+
// Optionals already worked, but let's just be sure
26+
public func f4() -> (some P)? {
27+
return self
28+
}
29+
30+
// Make sure we can handle a function conversion *and* opaque type erasure;
31+
// here we first convert (Any) -> (Self) to (Int) -> (Self) before erasing
32+
// to (Int) -> (some P)
33+
public func f5() -> (Int) -> (some P) {
34+
let fn: (Any) -> (Self) = { _ in self }
35+
return fn
36+
}
37+
}
38+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking
2+
3+
protocol P {
4+
init()
5+
}
6+
7+
extension P {
8+
static func opaqueProtocolExtensionFunc() -> some P { return Self() }
9+
}
10+
11+
class C: P {
12+
required init() {}
13+
14+
static func opaqueFunc1() -> some P {
15+
return Self()
16+
// expected-error@-1 {{function with opaque return type cannot return the covariant 'Self' type of a class}}
17+
}
18+
19+
static func opaqueFunc2() -> some P {
20+
return Self.opaqueProtocolExtensionFunc()
21+
// expected-error@-1 {{function with opaque return type cannot return the covariant 'Self' type of a class}}
22+
}
23+
24+
var opaqueProperty: some P {
25+
return Self()
26+
// expected-error@-1 {{function with opaque return type cannot return the covariant 'Self' type of a class}}
27+
}
28+
29+
subscript() -> some P {
30+
return Self()
31+
// expected-error@-1 {{function with opaque return type cannot return the covariant 'Self' type of a class}}
32+
}
33+
34+
var opaqueStoredProperty: some P = Self()
35+
// expected-error@-1 {{covariant 'Self' type cannot be referenced from a stored property initializer}}
36+
}

0 commit comments

Comments
 (0)