Skip to content

Sema: don't consider opaque types distinct for overloading purposes. #24166

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
merged 1 commit into from
Apr 26, 2019
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
5 changes: 4 additions & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,14 @@ struct OverloadSignature {
/// Whether this signature is of a member defined in an extension of a generic
/// type.
unsigned InExtensionOfGenericType : 1;

/// Whether this declaration has an opaque return type.
unsigned HasOpaqueReturnType : 1;

OverloadSignature()
: UnaryOperator(UnaryOperatorKind::None), IsInstanceMember(false),
IsVariable(false), IsFunction(false), InProtocolExtension(false),
InExtensionOfGenericType(false) {}
InExtensionOfGenericType(false), HasOpaqueReturnType(false) {}
};

/// Determine whether two overload signatures conflict.
Expand Down
8 changes: 8 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -4687,6 +4687,14 @@ class ArchetypeType : public SubstitutableType,

/// Get the generic environment this archetype lives in.
GenericEnvironment *getGenericEnvironment() const;

/// Get the protocol/class existential type that most closely represents the
/// set of constraints on this archetype.
///
/// Right now, this only considers constraints on the archetype itself, not
/// any of its associated types, since those are the only kind of existential
/// type we can represent.
Type getExistentialType() const;

// Implement isa/cast/dyncast/etc.
static bool classof(const TypeBase *T) {
Expand Down
15 changes: 15 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2092,6 +2092,10 @@ bool swift::conflicting(const OverloadSignature& sig1,
(sig2.IsVariable && !sig1.Name.getArgumentNames().empty()));
}

// Note that we intentionally ignore the HasOpaqueReturnType bit here.
// For declarations that can't be overloaded by type, we want them to be
// considered conflicting independent of their type.

return sig1.Name == sig2.Name;
}

Expand Down Expand Up @@ -2156,6 +2160,9 @@ bool swift::conflicting(ASTContext &ctx,
}

// Otherwise, the declarations conflict if the overload types are the same.
if (sig1.HasOpaqueReturnType != sig2.HasOpaqueReturnType)
return false;

if (sig1Type != sig2Type)
return false;

Expand Down Expand Up @@ -2246,6 +2253,12 @@ static Type mapSignatureFunctionType(ASTContext &ctx, Type type,
type = objectType;
}
}

// Functions and subscripts cannot overload differing only in opaque return
// types. Replace the opaque type with `Any`.
if (auto opaque = type->getAs<OpaqueTypeArchetypeType>()) {
type = opaque->getExistentialType();
}

return mapSignatureParamType(ctx, type);
}
Expand Down Expand Up @@ -2295,6 +2308,8 @@ OverloadSignature ValueDecl::getOverloadSignature() const {
signature.IsEnumElement = isa<EnumElementDecl>(this);
signature.IsNominal = isa<NominalTypeDecl>(this);
signature.IsTypeAlias = isa<TypeAliasDecl>(this);
signature.HasOpaqueReturnType =
!signature.IsVariable && (bool)getOpaqueResultTypeDecl();

// Unary operators also include prefix/postfix.
if (auto func = dyn_cast<FuncDecl>(this)) {
Expand Down
18 changes: 18 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2378,6 +2378,24 @@ ArchetypeType *ArchetypeType::getRoot() const {
return const_cast<ArchetypeType*>(parent);
}

Type ArchetypeType::getExistentialType() const {
// Opened types hold this directly.
if (auto opened = dyn_cast<OpenedArchetypeType>(this))
return opened->getOpenedExistentialType();

// Otherwise, compute it from scratch.
SmallVector<Type, 4> constraintTypes;

if (auto super = getSuperclass()) {
constraintTypes.push_back(super);
}
for (auto proto : getConformsTo()) {
constraintTypes.push_back(proto->getDeclaredType());
}
return ProtocolCompositionType::get(
const_cast<ArchetypeType*>(this)->getASTContext(), constraintTypes, false);
}

PrimaryArchetypeType::PrimaryArchetypeType(const ASTContext &Ctx,
GenericEnvironment *GenericEnv,
Type InterfaceType,
Expand Down
27 changes: 26 additions & 1 deletion test/type/opaque.swift
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,29 @@ var DoesNotConformComputedProp: some P {
}
*/


func redeclaration() -> some P { return 0 } // expected-note{{previously declared}}
func redeclaration() -> some P { return 0 } // expected-error{{redeclaration}}
func redeclaration() -> some Q { return 0 }
func redeclaration() -> P { return 0 }

var redeclaredProp: some P { return 0 } // expected-note 3{{previously declared}}
var redeclaredProp: some P { return 0 } // expected-error{{redeclaration}}
var redeclaredProp: some Q { return 0 } // expected-error{{redeclaration}}
var redeclaredProp: P { return 0 } // expected-error{{redeclaration}}

struct RedeclarationTest {
func redeclaration() -> some P { return 0 } // expected-note{{previously declared}}
func redeclaration() -> some P { return 0 } // expected-error{{redeclaration}}
func redeclaration() -> some Q { return 0 }
func redeclaration() -> P { return 0 }

var redeclaredProp: some P { return 0 } // expected-note 3{{previously declared}}
var redeclaredProp: some P { return 0 } // expected-error{{redeclaration}}
var redeclaredProp: some Q { return 0 } // expected-error{{redeclaration}}
var redeclaredProp: P { return 0 } // expected-error{{redeclaration}}

subscript(redeclared _: Int) -> some P { return 0 } // expected-note{{previously declared}}
subscript(redeclared _: Int) -> some P { return 0 } // expected-error{{redeclaration}}
subscript(redeclared _: Int) -> some Q { return 0 }
subscript(redeclared _: Int) -> P { return 0 }
}