Skip to content

Commit b2d50c8

Browse files
committed
Sema: don't consider opaque types distinct for overloading purposes.
This is necessary because: ``` func foo() -> some P func foo() -> some P ``` theoretically defines two distinct return types, but there'd be no way to disambiguate them. Disallow overloading only by opaque return type.
1 parent 84d96ad commit b2d50c8

File tree

5 files changed

+71
-2
lines changed

5 files changed

+71
-2
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,14 @@ struct OverloadSignature {
232232
/// Whether this signature is of a member defined in an extension of a generic
233233
/// type.
234234
unsigned InExtensionOfGenericType : 1;
235+
236+
/// Whether this declaration has an opaque return type.
237+
unsigned HasOpaqueReturnType : 1;
235238

236239
OverloadSignature()
237240
: UnaryOperator(UnaryOperatorKind::None), IsInstanceMember(false),
238241
IsVariable(false), IsFunction(false), InProtocolExtension(false),
239-
InExtensionOfGenericType(false) {}
242+
InExtensionOfGenericType(false), HasOpaqueReturnType(false) {}
240243
};
241244

242245
/// Determine whether two overload signatures conflict.

include/swift/AST/Types.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4687,6 +4687,14 @@ class ArchetypeType : public SubstitutableType,
46874687

46884688
/// Get the generic environment this archetype lives in.
46894689
GenericEnvironment *getGenericEnvironment() const;
4690+
4691+
/// Get the protocol/class existential type that most closely represents the
4692+
/// set of constraints on this archetype.
4693+
///
4694+
/// Right now, this only considers constraints on the archetype itself, not
4695+
/// any of its associated types, since those are the only kind of existential
4696+
/// type we can represent.
4697+
Type getExistentialType() const;
46904698

46914699
// Implement isa/cast/dyncast/etc.
46924700
static bool classof(const TypeBase *T) {

lib/AST/Decl.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,10 @@ bool swift::conflicting(const OverloadSignature& sig1,
20922092
(sig2.IsVariable && !sig1.Name.getArgumentNames().empty()));
20932093
}
20942094

2095+
// Note that we intentionally ignore the HasOpaqueReturnType bit here.
2096+
// For declarations that can't be overloaded by type, we want them to be
2097+
// considered conflicting independent of their type.
2098+
20952099
return sig1.Name == sig2.Name;
20962100
}
20972101

@@ -2156,6 +2160,9 @@ bool swift::conflicting(ASTContext &ctx,
21562160
}
21572161

21582162
// Otherwise, the declarations conflict if the overload types are the same.
2163+
if (sig1.HasOpaqueReturnType != sig2.HasOpaqueReturnType)
2164+
return false;
2165+
21592166
if (sig1Type != sig2Type)
21602167
return false;
21612168

@@ -2246,6 +2253,12 @@ static Type mapSignatureFunctionType(ASTContext &ctx, Type type,
22462253
type = objectType;
22472254
}
22482255
}
2256+
2257+
// Functions and subscripts cannot overload differing only in opaque return
2258+
// types. Replace the opaque type with `Any`.
2259+
if (auto opaque = type->getAs<OpaqueTypeArchetypeType>()) {
2260+
type = opaque->getExistentialType();
2261+
}
22492262

22502263
return mapSignatureParamType(ctx, type);
22512264
}
@@ -2295,6 +2308,8 @@ OverloadSignature ValueDecl::getOverloadSignature() const {
22952308
signature.IsEnumElement = isa<EnumElementDecl>(this);
22962309
signature.IsNominal = isa<NominalTypeDecl>(this);
22972310
signature.IsTypeAlias = isa<TypeAliasDecl>(this);
2311+
signature.HasOpaqueReturnType =
2312+
!signature.IsVariable && (bool)getOpaqueResultTypeDecl();
22982313

22992314
// Unary operators also include prefix/postfix.
23002315
if (auto func = dyn_cast<FuncDecl>(this)) {

lib/AST/Type.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2378,6 +2378,24 @@ ArchetypeType *ArchetypeType::getRoot() const {
23782378
return const_cast<ArchetypeType*>(parent);
23792379
}
23802380

2381+
Type ArchetypeType::getExistentialType() const {
2382+
// Opened types hold this directly.
2383+
if (auto opened = dyn_cast<OpenedArchetypeType>(this))
2384+
return opened->getOpenedExistentialType();
2385+
2386+
// Otherwise, compute it from scratch.
2387+
SmallVector<Type, 4> constraintTypes;
2388+
2389+
if (auto super = getSuperclass()) {
2390+
constraintTypes.push_back(super);
2391+
}
2392+
for (auto proto : getConformsTo()) {
2393+
constraintTypes.push_back(proto->getDeclaredType());
2394+
}
2395+
return ProtocolCompositionType::get(
2396+
const_cast<ArchetypeType*>(this)->getASTContext(), constraintTypes, false);
2397+
}
2398+
23812399
PrimaryArchetypeType::PrimaryArchetypeType(const ASTContext &Ctx,
23822400
GenericEnvironment *GenericEnv,
23832401
Type InterfaceType,

test/type/opaque.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,4 +287,29 @@ var DoesNotConformComputedProp: some P {
287287
}
288288
*/
289289

290-
290+
func redeclaration() -> some P { return 0 } // expected-note{{previously declared}}
291+
func redeclaration() -> some P { return 0 } // expected-error{{redeclaration}}
292+
func redeclaration() -> some Q { return 0 }
293+
func redeclaration() -> P { return 0 }
294+
295+
var redeclaredProp: some P { return 0 } // expected-note 3{{previously declared}}
296+
var redeclaredProp: some P { return 0 } // expected-error{{redeclaration}}
297+
var redeclaredProp: some Q { return 0 } // expected-error{{redeclaration}}
298+
var redeclaredProp: P { return 0 } // expected-error{{redeclaration}}
299+
300+
struct RedeclarationTest {
301+
func redeclaration() -> some P { return 0 } // expected-note{{previously declared}}
302+
func redeclaration() -> some P { return 0 } // expected-error{{redeclaration}}
303+
func redeclaration() -> some Q { return 0 }
304+
func redeclaration() -> P { return 0 }
305+
306+
var redeclaredProp: some P { return 0 } // expected-note 3{{previously declared}}
307+
var redeclaredProp: some P { return 0 } // expected-error{{redeclaration}}
308+
var redeclaredProp: some Q { return 0 } // expected-error{{redeclaration}}
309+
var redeclaredProp: P { return 0 } // expected-error{{redeclaration}}
310+
311+
subscript(redeclared _: Int) -> some P { return 0 } // expected-note{{previously declared}}
312+
subscript(redeclared _: Int) -> some P { return 0 } // expected-error{{redeclaration}}
313+
subscript(redeclared _: Int) -> some Q { return 0 }
314+
subscript(redeclared _: Int) -> P { return 0 }
315+
}

0 commit comments

Comments
 (0)