Skip to content

[01-02-2019] Opaque result types #22042

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
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
2 changes: 2 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ namespace swift {
class ModuleLoader;
class NominalTypeDecl;
class NormalProtocolConformance;
class OpaqueTypeDecl;
class InheritedProtocolConformance;
class SelfProtocolConformance;
class SpecializedProtocolConformance;
Expand Down Expand Up @@ -942,6 +943,7 @@ class ASTContext final {

friend TypeBase;
friend ArchetypeType;
friend OpaqueTypeDecl;

/// Provide context-level uniquing for SIL lowered type layouts and boxes.
friend SILLayout;
Expand Down
87 changes: 85 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ enum class DescriptiveDeclKind : uint8_t {
Module,
MissingMember,
Requirement,
OpaqueType,
};

/// Keeps track of stage of circularity checking for the given protocol.
Expand Down Expand Up @@ -2294,6 +2295,8 @@ class PoundDiagnosticDecl : public Decl {
return D->getKind() == DeclKind::PoundDiagnostic;
}
};

class OpaqueTypeDecl;

/// ValueDecl - All named decls that are values in the language. These can
/// have a type, etc.
Expand Down Expand Up @@ -2650,6 +2653,15 @@ class ValueDecl : public Decl {
/// True if this is a C function that was imported as a member of a type in
/// Swift.
bool isImportAsMember() const;

/// Get the decl for this value's opaque result type, if it has one.
OpaqueTypeDecl *getOpaqueResultTypeDecl() const;

/// Set the opaque return type decl for this decl.
///
/// `this` must be of a decl type that supports opaque return types, and
/// must not have previously had an opaque result type set.
void setOpaqueResultTypeDecl(OpaqueTypeDecl *D);
};

/// This is a common base class for declarations which declare a type.
Expand Down Expand Up @@ -2700,7 +2712,7 @@ class TypeDecl : public ValueDecl {
}
};

/// A type declaration that can have generic parameters attached to it. Because
/// A type declaration that can have generic parameters attached to it. Because
/// it has these generic parameters, it is always a DeclContext.
class GenericTypeDecl : public GenericContext, public TypeDecl {
public:
Expand All @@ -2725,7 +2737,69 @@ class GenericTypeDecl : public GenericContext, public TypeDecl {
}
};


/// OpaqueTypeDecl - This is a declaration of an opaque type. The opaque type
/// is formally equivalent to its underlying type, but abstracts it away from
/// clients of the opaque type, only exposing the type as something conforming
/// to a given set of constraints.
///
/// Currently, opaque types do not normally have an explicit spelling in source
/// code. One is formed implicitly when a declaration is written with an opaque
/// result type, as in:
///
/// func foo() -> opaque SignedInteger { return 1 }
///
/// The declared type is a special kind of ArchetypeType representing the
/// abstracted underlying type.
class OpaqueTypeDecl : public GenericTypeDecl {
/// The original declaration that "names" the opaque type. Although a specific
/// opaque type cannot be explicitly named, oapque types can propagate
/// arbitrarily through expressions, so we need to know *which* opaque type is
/// propagated.
ValueDecl *NamingDecl;

/// The generic signature of the opaque interface to the type. This is the
/// outer generic signature with an added generic parameter representing the
/// underlying type.
GenericSignature *OpaqueInterfaceGenericSignature;

/// The generic parameter that represents the underlying type.
GenericTypeParamType *UnderlyingInterfaceType;

/// If known, the underlying type and conformances of the opaque type,
/// expressed as a SubstitutionMap for the opaque interface generic signature.
/// This maps types in the interface generic signature to the outer generic
/// signature of the original declaration.
Optional<SubstitutionMap> UnderlyingTypeSubstitutions;

public:
OpaqueTypeDecl(ValueDecl *NamingDecl,
GenericParamList *GenericParams,
DeclContext *DC,
GenericSignature *OpaqueInterfaceGenericSignature,
GenericTypeParamType *UnderlyingInterfaceType);

ValueDecl *getNamingDecl() const { return NamingDecl; }

GenericSignature *getOpaqueInterfaceGenericSignature() const {
return OpaqueInterfaceGenericSignature;
}

GenericTypeParamType *getUnderlyingInterfaceType() const {
return UnderlyingInterfaceType;
}

Optional<SubstitutionMap> getUnderlyingTypeSubstitutions() const {
return UnderlyingTypeSubstitutions;
}

void setUnderlyingTypeSubstitutions(SubstitutionMap subs) {
assert(!UnderlyingTypeSubstitutions.hasValue() && "resetting underlying type?!");
UnderlyingTypeSubstitutions = subs;
}

// Opaque type decls are currently always implicit
SourceRange getSourceRange() const { return SourceRange(); }
};

/// TypeAliasDecl - This is a declaration of a typealias, for example:
///
Expand Down Expand Up @@ -5499,6 +5573,7 @@ class FuncDecl : public AbstractFunctionDecl {
TypeLoc FnRetType;

OperatorDecl *Operator = nullptr;
OpaqueTypeDecl *OpaqueReturn = nullptr;

protected:
FuncDecl(DeclKind Kind,
Expand Down Expand Up @@ -5652,6 +5727,14 @@ class FuncDecl : public AbstractFunctionDecl {
Operator = o;
}

OpaqueTypeDecl *getOpaqueResultTypeDecl() const {
return OpaqueReturn;
}
void setOpaqueResultTypeDecl(OpaqueTypeDecl *decl) {
assert(!OpaqueReturn && "already has opaque type decl");
OpaqueReturn = decl;
}

/// Returns true if the function is forced to be statically dispatched.
bool hasForcedStaticDispatch() const {
return Bits.FuncDecl.ForcedStaticDispatch;
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/DeclNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ ABSTRACT_DECL(Value, Decl)
NOMINAL_TYPE_DECL(Class, NominalTypeDecl)
NOMINAL_TYPE_DECL(Protocol, NominalTypeDecl)
DECL_RANGE(NominalType, Enum, Protocol)
GENERIC_VALUE_DECL(OpaqueType, GenericTypeDecl)
GENERIC_VALUE_DECL(TypeAlias, GenericTypeDecl)
DECL_RANGE(GenericType, Enum, TypeAlias)
ABSTRACT_DECL(AbstractTypeParam, TypeDecl)
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,10 @@ ERROR(sil_box_expected_r_brace,none,
ERROR(sil_box_expected_r_angle,none,
"expected '>' to complete SIL box generic argument list", ())

// Opaque types
ERROR(opaque_mid_composition,none,
"'opaque' should appear at the beginning of a composition", ())

//------------------------------------------------------------------------------
// MARK: Layout constraint diagnostics
//------------------------------------------------------------------------------
Expand Down
21 changes: 21 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1503,6 +1503,11 @@ ERROR(noreturn_not_supported,none,
"'@noreturn' has been removed; functions that never return should have a "
"return type of 'Never' instead", ())

// Opaque return types
ERROR(opaque_type_invalid_constraint,none,
"an 'opaque' type must specify only 'Any', 'AnyObject', protocols, "
"and/or a base class", ())

// Extensions
ERROR(non_nominal_extension,none,
"non-nominal type %0 cannot be extended", (Type))
Expand Down Expand Up @@ -3204,6 +3209,18 @@ ERROR(trailing_closure_requires_parens,none,
"trailing closure requires parentheses for disambiguation in this"
" context", ())

ERROR(opaque_type_no_underlying_type_candidates,none,
"function declares an opaque return type, but has no return statements "
"in its body from which to infer an underlying type", ())
ERROR(opaque_type_mismatched_underlying_type_candidates,none,
"function declares an opaque return type, but the return statements "
"in its body do not have matching underlying types", ())
NOTE(opaque_type_underlying_type_candidate_here,none,
"return statement has underlying type %0", (Type))
ERROR(opaque_type_self_referential_underlying_type,none,
"function opaque return type was inferred as %0, which defines the "
"opaque type in terms of itself", (Type))

//------------------------------------------------------------------------------
// MARK: Type Check Patterns
//------------------------------------------------------------------------------
Expand Down Expand Up @@ -3514,6 +3531,10 @@ ERROR(unsupported_convention,none,
ERROR(unreferenced_generic_parameter,none,
"generic parameter '%0' is not used in function signature", (StringRef))

// Opaque types
ERROR(unsupported_opaque_type,none,
"'opaque' types are only implemented for the declared type of properties and subscripts and the return type of functions", ())

// SIL
ERROR(opened_non_protocol,none,
"@opened cannot be applied to non-protocol type %0", (Type))
Expand Down
11 changes: 11 additions & 0 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2871,6 +2871,17 @@ class UnevaluatedInstanceExpr : public ImplicitConversionExpr {
}
};

/// Use an opaque type to abstract a value of the underlying concrete type.
class UnderlyingToOpaqueExpr : public ImplicitConversionExpr {
public:
UnderlyingToOpaqueExpr(Expr *subExpr, Type ty)
: ImplicitConversionExpr(ExprKind::UnderlyingToOpaque, subExpr, ty) {}

static bool classof(const Expr *E) {
return E->getKind() == ExprKind::UnderlyingToOpaque;
}
};

/// TupleShuffleExpr - This represents a permutation of a tuple value to a new
/// tuple type.
///
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/ExprNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ ABSTRACT_EXPR(ImplicitConversion, Expr)
EXPR(PointerToPointer, ImplicitConversionExpr)
EXPR(ForeignObjectConversion, ImplicitConversionExpr)
EXPR(UnevaluatedInstance, ImplicitConversionExpr)
EXPR_RANGE(ImplicitConversion, Load, UnevaluatedInstance)
EXPR(UnderlyingToOpaque, ImplicitConversionExpr)
EXPR_RANGE(ImplicitConversion, Load, UnderlyingToOpaque)
ABSTRACT_EXPR(ExplicitCast, Expr)
ABSTRACT_EXPR(CheckedCast, ExplicitCastExpr)
EXPR(ForcedCheckedCast, CheckedCastExpr)
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/GenericSignature.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,10 @@ class alignas(1 << TypeAlignInBits) GenericSignature final
/// <t_0_0, t_0_1, t_1_0>
/// then this will return 0 for t_0_0, 1 for t_0_1, and 2 for t_1_0.
unsigned getGenericParamOrdinal(GenericTypeParamType *param);

/// Get a substitution map that maps all of the generic signature's
/// generic parameters to themselves.
SubstitutionMap getIdentitySubstitutionMap() const;

static void Profile(llvm::FoldingSetNodeID &ID,
TypeArrayView<GenericTypeParamType> genericParams,
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
/// Substitute the conforming type and produce a ProtocolConformance that
/// applies to the substituted type.
ProtocolConformance *subst(TypeSubstitutionFn subs,
LookupConformanceFn conformances) const;
LookupConformanceFn conformances,
SubstOptions options = None) const;

void dump() const;
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;
Expand Down
7 changes: 6 additions & 1 deletion include/swift/AST/ProtocolConformanceRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,13 @@ class ProtocolConformanceRef {
/// Apply a substitution to the conforming type.
ProtocolConformanceRef subst(Type origType,
TypeSubstitutionFn subs,
LookupConformanceFn conformances) const;
LookupConformanceFn conformances,
SubstOptions options = None) const;

/// Replace opaque types in the conforming type with their underlying types,
/// and resolve opaque conformances to their underlying conformances.
ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypes(Type origType) const;

/// Given a dependent type (expressed in terms of this conformance's
/// protocol), follow it from the conforming type.
Type getAssociatedType(Type origType, Type dependentType,
Expand Down
7 changes: 6 additions & 1 deletion include/swift/AST/SubstitutionMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,12 @@ class SubstitutionMap {
/// Apply a substitution to all replacement types in the map. Does not
/// change keys.
SubstitutionMap subst(TypeSubstitutionFn subs,
LookupConformanceFn conformances) const;
LookupConformanceFn conformances,
SubstOptions options = None) const;

/// Replace opaque types in the replacement types in the map with their
/// underlying types. Does not change keys.
SubstitutionMap substOpaqueTypesWithUnderlyingTypes() const;

/// Create a substitution map for a protocol conformance.
static SubstitutionMap
Expand Down
9 changes: 8 additions & 1 deletion include/swift/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class TypeBase;
class Type;
class TypeWalker;
struct ExistentialLayout;

enum class ResilienceExpansion : unsigned;

/// Type substitution mapping from substitutable types to their
/// replacements.
typedef llvm::DenseMap<SubstitutableType *, Type> TypeSubstitutionMap;
Expand Down Expand Up @@ -147,6 +148,8 @@ enum class SubstFlags {
AllowLoweredTypes = 0x02,
/// Map member types to their desugared witness type.
DesugarMemberTypes = 0x04,
/// Substitute types involving opaque type archetypes.
SubstituteOpaqueArchetypes = 0x08,
};

/// Options for performing substitutions into a type.
Expand Down Expand Up @@ -312,6 +315,10 @@ class Type {

/// Replace references to substitutable types with error types.
Type substDependentTypesWithErrorTypes() const;

/// Replace opaque types with their underlying types when visible at the given
/// resilience expansion.
Type substOpaqueTypesWithUnderlyingTypes() const;

bool isPrivateStdlibType(bool treatNonBuiltinProtocolsAsPublic = true) const;

Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/TypeNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ TYPE(DynamicSelf, Type)
ABSTRACT_TYPE(Substitutable, Type)
ABSTRACT_TYPE(Archetype, SubstitutableType)
ALWAYS_CANONICAL_TYPE(PrimaryArchetype, ArchetypeType)
ALWAYS_CANONICAL_TYPE(OpaqueTypeArchetype, ArchetypeType)
ALWAYS_CANONICAL_TYPE(OpenedArchetype, ArchetypeType)
ALWAYS_CANONICAL_TYPE(NestedArchetype, ArchetypeType)
TYPE_RANGE(Archetype, PrimaryArchetype, NestedArchetype)
Expand Down
40 changes: 40 additions & 0 deletions include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,45 @@ class SILBoxTypeReprField {
TypeRepr *getFieldType() const { return FieldTypeAndMutable.getPointer(); }
bool isMutable() const { return FieldTypeAndMutable.getInt(); }
};

/// TypeRepr for opaque return types.
///
/// This can occur in the return position of a function declaration, or the
/// top-level type of a property, to specify that the concrete return type
/// should be abstracted from callers, given a set of generic constraints that
/// the concrete return type satisfies:
///
/// func foo() -> opaque Collection { return [1,2,3] }
/// var bar: opaque SignedInteger = 1
///
/// It is currently illegal for this to appear in any other position.
class OpaqueReturnTypeRepr : public TypeRepr {
/// The type repr for the immediate constraints on the opaque type.
/// In valid code this must resolve to a class, protocol, or composition type.
TypeRepr *Constraint;
SourceLoc OpaqueLoc;

public:
OpaqueReturnTypeRepr(SourceLoc opaqueLoc, TypeRepr *constraint)
: TypeRepr(TypeReprKind::OpaqueReturn), Constraint(constraint),
OpaqueLoc(opaqueLoc)
{}

TypeRepr *getConstraint() const { return Constraint; }
SourceLoc getOpaqueLoc() const { return OpaqueLoc; }

static bool classof(const TypeRepr *T) {
return T->getKind() == TypeReprKind::OpaqueReturn;
}
static bool classof(const OpaqueReturnTypeRepr *T) { return true; }

private:
SourceLoc getStartLocImpl() const { return OpaqueLoc; }
SourceLoc getEndLocImpl() const { return Constraint->getEndLoc(); }
SourceLoc getLocImpl() const { return OpaqueLoc; }
void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const;
friend class TypeRepr;
};

/// SIL-only TypeRepr for box types.
///
Expand Down Expand Up @@ -1108,6 +1147,7 @@ inline bool TypeRepr::isSimple() const {
case TypeReprKind::Function:
case TypeReprKind::InOut:
case TypeReprKind::Composition:
case TypeReprKind::OpaqueReturn:
return false;
case TypeReprKind::SimpleIdent:
case TypeReprKind::GenericIdent:
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/TypeReprNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ TYPEREPR(Tuple, TypeRepr)
TYPEREPR(Composition, TypeRepr)
TYPEREPR(Metatype, TypeRepr)
TYPEREPR(Protocol, TypeRepr)
TYPEREPR(OpaqueReturn, TypeRepr)
ABSTRACT_TYPEREPR(Specifier, TypeRepr)
TYPEREPR(InOut, SpecifierTypeRepr)
TYPEREPR(Shared, SpecifierTypeRepr)
Expand Down
Loading