diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 05abe1e446602..3d6228210e3dc 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -84,6 +84,7 @@ namespace swift { class ModuleLoader; class NominalTypeDecl; class NormalProtocolConformance; + class OpaqueTypeDecl; class InheritedProtocolConformance; class SelfProtocolConformance; class SpecializedProtocolConformance; @@ -952,6 +953,7 @@ class ASTContext final { friend TypeBase; friend ArchetypeType; + friend OpaqueTypeDecl; /// Provide context-level uniquing for SIL lowered type layouts and boxes. friend SILLayout; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index b54ffe2574d31..027b5421601a0 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -158,6 +158,7 @@ enum class DescriptiveDeclKind : uint8_t { Module, MissingMember, Requirement, + OpaqueType, }; /// Keeps track of stage of circularity checking for the given protocol. @@ -2299,6 +2300,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. @@ -2659,6 +2662,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. @@ -2709,7 +2721,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: @@ -2734,7 +2746,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 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 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: /// @@ -5524,6 +5598,7 @@ class FuncDecl : public AbstractFunctionDecl { TypeLoc FnRetType; OperatorDecl *Operator = nullptr; + OpaqueTypeDecl *OpaqueReturn = nullptr; protected: FuncDecl(DeclKind Kind, @@ -5677,6 +5752,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; diff --git a/include/swift/AST/DeclNodes.def b/include/swift/AST/DeclNodes.def index 5aeef91652096..67c0decf6216d 100644 --- a/include/swift/AST/DeclNodes.def +++ b/include/swift/AST/DeclNodes.def @@ -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) diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index fac18957f641b..bd2746033d608 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -786,6 +786,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 //------------------------------------------------------------------------------ diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 9f126a99e3527..568991f55275a 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1505,6 +1505,14 @@ WARNING(function_type_usable_from_inline_warn,none, "should be '@usableFromInline' or public", (unsigned, bool)) +// Opaque return types +ERROR(opaque_type_invalid_constraint,none, + "an 'opaque' type must specify only 'Any', 'AnyObject', protocols, " + "and/or a base class", ()) +ERROR(inferred_opaque_type,none, + "property definition has inferred type %0, involving the '__opaque' " + "return type of another declaration", (Type)) + // Extensions ERROR(non_nominal_extension,none, "non-nominal type %0 cannot be extended", (Type)) @@ -3223,6 +3231,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 //------------------------------------------------------------------------------ @@ -3533,6 +3553,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)) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 2e175ed0bcaa2..c2b312e292bae 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -2948,6 +2948,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. /// diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index 84d49ebe617d5..b4e40a9341c17 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -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) diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index d51a9c7960a55..4ab856af978fa 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -307,6 +307,10 @@ class alignas(1 << TypeAlignInBits) GenericSignature final /// /// 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 genericParams, diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index 400aa3d6d9f63..c8aaf63db1259 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -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; diff --git a/include/swift/AST/ProtocolConformanceRef.h b/include/swift/AST/ProtocolConformanceRef.h index 716ce48d4735d..1677307571256 100644 --- a/include/swift/AST/ProtocolConformanceRef.h +++ b/include/swift/AST/ProtocolConformanceRef.h @@ -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, diff --git a/include/swift/AST/SubstitutionMap.h b/include/swift/AST/SubstitutionMap.h index d0caa24e0698c..7b4e9ee80898c 100644 --- a/include/swift/AST/SubstitutionMap.h +++ b/include/swift/AST/SubstitutionMap.h @@ -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 diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h index 8f7e3c4130d10..923ae94ddc7a0 100644 --- a/include/swift/AST/Type.h +++ b/include/swift/AST/Type.h @@ -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 TypeSubstitutionMap; @@ -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. @@ -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; diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index fd054839041e8..1e15e580f2ff9 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -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) diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 188dc2fd9ca65..3d3b6674ac925 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -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. /// @@ -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: diff --git a/include/swift/AST/TypeReprNodes.def b/include/swift/AST/TypeReprNodes.def index f5ebe09993737..653af0b565540 100644 --- a/include/swift/AST/TypeReprNodes.def +++ b/include/swift/AST/TypeReprNodes.def @@ -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) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 5a51f0c5156e0..b94b5caa47767 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -53,8 +53,10 @@ namespace swift { class GenericTypeParamType; class GenericParamList; class GenericSignature; + class GenericSignatureBuilder; class Identifier; class InOutType; + class OpaqueTypeDecl; class OpenedArchetypeType; enum class ReferenceCounting : uint8_t; enum class ResilienceExpansion : unsigned; @@ -98,7 +100,8 @@ class RecursiveTypeProperties { /// This type expression contains a TypeVariableType. HasTypeVariable = 0x01, - /// This type expression contains an ArchetypeType. + /// This type expression contains a context-dependent archetype, either a + /// PrimaryArchetypeType or OpenedArchetypeType. HasArchetype = 0x02, /// This type expression contains a GenericTypeParamType. @@ -125,8 +128,11 @@ class RecursiveTypeProperties { /// This type contains a DependentMemberType. HasDependentMember = 0x200, + + /// This type contains an OpaqueTypeArchetype. + HasOpaqueArchetype = 0x400, - Last_Property = HasDependentMember + Last_Property = HasOpaqueArchetype }; enum { BitWidth = countBitsUsed(Property::Last_Property) }; @@ -145,10 +151,14 @@ class RecursiveTypeProperties { /// variable? bool hasTypeVariable() const { return Bits & HasTypeVariable; } - /// Does a type with these properties structurally contain an - /// archetype? + /// Does a type with these properties structurally contain a + /// context-dependent archetype (that is, a Primary- or OpenedArchetype)? bool hasArchetype() const { return Bits & HasArchetype; } + /// Does a type with these properties structurally contain an + /// archetype from an opaque type declaration? + bool hasOpaqueArchetype() const { return Bits & HasOpaqueArchetype; } + /// Does a type with these properties have a type parameter somewhere in it? bool hasTypeParameter() const { return Bits & HasTypeParameter; } @@ -537,11 +547,11 @@ class alignas(1 << TypeAlignInBits) TypeBase { return getRecursiveProperties().hasUnresolvedType(); } - /// Determine whether the type involves an archetype. + /// Determine whether the type involves a context-dependent archetype. bool hasArchetype() const { return getRecursiveProperties().hasArchetype(); } - + /// Determine whether the type involves an opened existential archetype. bool hasOpenedExistential() const { return getRecursiveProperties().hasOpenedExistential(); @@ -551,6 +561,11 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// archetype. bool hasOpenedExistential(OpenedArchetypeType *opened); + /// Determine whether the type involves an opaque type. + bool hasOpaqueArchetype() const { + return getRecursiveProperties().hasOpaqueArchetype(); + } + /// Determine whether the type is an opened existential type. /// /// To determine whether there is an opened existential type @@ -4573,6 +4588,7 @@ using ArchetypeTrailingObjects = llvm::TrailingObjects; class PrimaryArchetypeType; +class OpaqueTypeArchetypeType; /// An archetype is a type that represents a runtime type that is /// known to conform to some set of requirements. @@ -4759,6 +4775,90 @@ class PrimaryArchetypeType final : public ArchetypeType, BEGIN_CAN_TYPE_WRAPPER(PrimaryArchetypeType, ArchetypeType) END_CAN_TYPE_WRAPPER(PrimaryArchetypeType, ArchetypeType) +/// An archetype that represents an opaque type. +class OpaqueTypeArchetypeType final : public ArchetypeType, + public llvm::FoldingSetNode, + private ArchetypeTrailingObjects +{ + friend TrailingObjects; + friend ArchetypeType; + friend GenericSignatureBuilder; + + /// The declaration that defines the opaque type. + OpaqueTypeDecl *OpaqueDecl; + /// The substitutions into the interface signature of the opaque type. + SubstitutionMap Substitutions; + + /// A GenericEnvironment with this opaque archetype bound to the interface + /// type of the output type from the OpaqueDecl. + GenericEnvironment *Environment; + +public: + /// Get + + /// Get an opaque archetype representing the underlying type of the given + /// opaque type decl. + static OpaqueTypeArchetypeType *get(OpaqueTypeDecl *Decl, + SubstitutionMap Substitutions); + + OpaqueTypeDecl *getOpaqueDecl() const { + return OpaqueDecl; + } + SubstitutionMap getSubstitutions() const { + return Substitutions; + } + + /// Get the generic signature used to build out this archetype. This is + /// equivalent to the OpaqueTypeDecl's interface generic signature, with + /// all of the generic parameters aside from the opaque type's interface + /// type same-type-constrained to their substitutions for this type. + GenericSignature *getBoundSignature() const; + + /// Get a generic environment that has this opaque archetype bound within it. + GenericEnvironment *getGenericEnvironment() const { + return Environment; + } + + static bool classof(const TypeBase *T) { + return T->getKind() == TypeKind::OpaqueTypeArchetype; + } + + static void Profile(llvm::FoldingSetNodeID &ID, + OpaqueTypeDecl *OpaqueDecl, + SubstitutionMap Substitutions); + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getOpaqueDecl(), getSubstitutions()); + }; + +private: + OpaqueTypeArchetypeType(OpaqueTypeDecl *OpaqueDecl, + SubstitutionMap Substitutions, + RecursiveTypeProperties Props, + Type InterfaceType, + ArrayRef ConformsTo, + Type Superclass, LayoutConstraint Layout); +}; +BEGIN_CAN_TYPE_WRAPPER(OpaqueTypeArchetypeType, ArchetypeType) +END_CAN_TYPE_WRAPPER(OpaqueTypeArchetypeType, ArchetypeType) + +/// A function object that can be used as a \c TypeSubstitutionFn and +/// \c LookupConformanceFn for \c Type::subst style APIs to map opaque +/// archetypes with underlying types visible at a given resilience expansion +/// to their underlying types. +class ReplaceOpaqueTypesWithUnderlyingTypes { +public: + ReplaceOpaqueTypesWithUnderlyingTypes() {} + + /// TypeSubstitutionFn + Type operator()(SubstitutableType *maybeOpaqueType) const; + + /// LookupConformanceFn + Optional operator()(CanType maybeOpaqueType, + Type replacementType, + ProtocolDecl *protocol) const; +}; + /// An archetype that represents the dynamic type of an opened existential. class OpenedArchetypeType final : public ArchetypeType, private ArchetypeTrailingObjects @@ -4865,6 +4965,9 @@ const Type *ArchetypeType::getSubclassTrailingObjects() const { if (auto contextTy = dyn_cast(this)) { return contextTy->getTrailingObjects(); } + if (auto opaqueTy = dyn_cast(this)) { + return opaqueTy->getTrailingObjects(); + } if (auto openedTy = dyn_cast(this)) { return openedTy->getTrailingObjects(); } @@ -5008,7 +5111,6 @@ BEGIN_CAN_TYPE_WRAPPER(DependentMemberType, Type) PROXY_CAN_TYPE_SIMPLE_GETTER(getBase) END_CAN_TYPE_WRAPPER(DependentMemberType, Type) - /// The storage type of a variable with non-strong reference /// ownership semantics. /// diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 9ca6f7aba08f9..f5e1441f59ae7 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -294,6 +294,9 @@ namespace swift { /// Scaffolding to permit experimentation with finer-grained dependencies /// and faster rebuilds. bool EnableExperimentalDependencies = false; + + /// Enable the experimental opaque result types feature. + bool EnableOpaqueResultTypes = true; /// To mimic existing system, set to false. /// To experiment with including file-private and private dependency info, diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index f792e5bc6f451..0804f303c0acf 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -403,6 +403,10 @@ def solver_enable_operator_designated_types : Flag<["-"], "solver-enable-operator-designated-types">, HelpText<"Enable operator designated types in constraint solver">; +def enable_opaque_result_types : + Flag<["-"], "enable-opaque-result-types">, + HelpText<"Enable experimental opaque result types feature">; + def switch_checking_invocation_threshold_EQ : Joined<["-"], "switch-checking-invocation-threshold=">; diff --git a/include/swift/Parse/Token.h b/include/swift/Parse/Token.h index d607ad3729a81..f4c72fc1877cf 100644 --- a/include/swift/Parse/Token.h +++ b/include/swift/Parse/Token.h @@ -165,6 +165,10 @@ class Token { if (getRawText().equals("__shared") || getRawText().equals("__owned")) return false; + + // ...or __opaque + if (getRawText().equals("__opaque")) + return false; return true; } diff --git a/include/swift/SIL/AbstractionPattern.h b/include/swift/SIL/AbstractionPattern.h index a160c66d6c6f7..546a378f2b4df 100644 --- a/include/swift/SIL/AbstractionPattern.h +++ b/include/swift/SIL/AbstractionPattern.h @@ -298,9 +298,16 @@ class AbstractionPattern { Kind kind = Kind::Type) { assert(signature || !origType->hasTypeParameter()); TheKind = unsigned(kind); - OrigType = origType; + // If origType is already a lowered type, it won't currently ever contain + // unsubstituted opaque types. + if (isa(origType)) + OrigType = origType; + else + OrigType = origType + .substOpaqueTypesWithUnderlyingTypes() + ->getCanonicalType(); GenericSig = CanGenericSignature(); - if (origType->hasTypeParameter()) + if (OrigType->hasTypeParameter()) GenericSig = signature; } diff --git a/include/swift/Serialization/DeclTypeRecordNodes.def b/include/swift/Serialization/DeclTypeRecordNodes.def index f911fe1124481..1df73b90c0c25 100644 --- a/include/swift/Serialization/DeclTypeRecordNodes.def +++ b/include/swift/Serialization/DeclTypeRecordNodes.def @@ -90,6 +90,7 @@ TRAILING_INFO(FUNCTION_PARAM) TYPE(METATYPE) TYPE(PRIMARY_ARCHETYPE) TYPE(OPENED_ARCHETYPE) +TYPE(OPAQUE_ARCHETYPE) TYPE(NESTED_ARCHETYPE) TYPE(PROTOCOL_COMPOSITION) TYPE(BOUND_GENERIC) @@ -116,6 +117,7 @@ DECL(CONSTRUCTOR) DECL(VAR) DECL(PARAM) DECL(FUNC) +DECL(OPAQUE_TYPE) DECL(PATTERN_BINDING) DECL(PROTOCOL) TRAILING_INFO(DEFAULT_WITNESS_TABLE) diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 638fbd841f961..9d90c2d3bd236 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 475; // Last change: Generalize nested archetype serialization +const uint16_t SWIFTMODULE_VERSION_MINOR = 476; // Last change: Opaque archetypes using DeclIDField = BCFixed<31>; @@ -778,6 +778,12 @@ namespace decls_block { TypeIDField // the existential type >; + using OpaqueArchetypeTypeLayout = BCRecordLayout< + OPAQUE_ARCHETYPE_TYPE, + DeclIDField, // the opaque type decl + SubstitutionMapIDField // the arguments + >; + using NestedArchetypeTypeLayout = BCRecordLayout< NESTED_ARCHETYPE_TYPE, TypeIDField, // root archetype @@ -1056,6 +1062,7 @@ namespace decls_block { AccessLevelField, // access level BCFixed<1>, // requires a new vtable slot BCFixed<1>, // default argument resilience expansion + DeclIDField, // opaque result type decl BCArray // name components, // followed by TypeID dependencies // The record is trailed by: @@ -1066,6 +1073,16 @@ namespace decls_block { // - inlinable body text, if any >; + using OpaqueTypeLayout = BCRecordLayout< + OPAQUE_TYPE_DECL, + DeclContextIDField, // decl context + DeclIDField, // naming decl + GenericSignatureIDField, // interface generic signature + TypeIDField, // interface type for opaque type + GenericEnvironmentIDField, // generic environment + SubstitutionMapIDField // optional substitution map for underlying type + >; + // TODO: remove the unnecessary FuncDecl components here using AccessorLayout = BCRecordLayout< ACCESSOR_DECL, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a1d3ce157a663..a5a2fee44d518 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -325,6 +325,7 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL) llvm::FoldingSet ProtocolTypes; llvm::FoldingSet ProtocolCompositionTypes; llvm::FoldingSet LayoutConstraints; + llvm::FoldingSet OpaqueArchetypes; /// The set of function types. llvm::FoldingSet FunctionTypes; @@ -3629,7 +3630,7 @@ isFunctionTypeCanonical(ArrayRef params, static RecursiveTypeProperties getGenericFunctionRecursiveProperties(ArrayRef params, Type result) { - static_assert(RecursiveTypeProperties::BitWidth == 10, + static_assert(RecursiveTypeProperties::BitWidth == 11, "revisit this if you add new recursive type properties"); RecursiveTypeProperties properties; @@ -4103,7 +4104,7 @@ CanSILFunctionType SILFunctionType::get(GenericSignature *genericSig, void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); RecursiveTypeProperties properties; - static_assert(RecursiveTypeProperties::BitWidth == 10, + static_assert(RecursiveTypeProperties::BitWidth == 11, "revisit this if you add new recursive type properties"); for (auto ¶m : params) properties |= param.getType()->getRecursiveProperties(); @@ -4275,6 +4276,139 @@ DependentMemberType *DependentMemberType::get(Type base, return known; } +OpaqueTypeArchetypeType * +OpaqueTypeArchetypeType::get(OpaqueTypeDecl *Decl, + SubstitutionMap Substitutions) { + // TODO: We could attempt to preserve type sugar in the substitution map. + Substitutions = Substitutions.getCanonical(); + + // TODO: Eventually an opaque archetype ought to be arbitrarily substitutable + // into any generic environment. However, there isn't currently a good way to + // do this with GenericSignatureBuilder; in a situation like this: + // + // __opaque_type Foo: Q // internal signature + // + // func bar() -> Foo + // + // we'd want to feed the GSB constraints to form: + // + // + // + // even though t_0_2 isn't *in* this generic signature; it represents a type + // bound elsewhere from some other generic context. If we knew the generic + // environment `t_0_2` came from, then maybe we could map it into that context, + // but currently we have no way to know that with certainty. + // + // For now, opaque types cannot propagate across decls; every declaration + // with an opaque type has a unique opaque decl. Therefore, the only + // expressions involving opaque types ought to be contextualized inside + // function bodies, and the only time we need an opaque interface type should + // be for the opaque decl itself and the originating decl with the opaque + // result type, in which case the interface type mapping is identity and + // this problem can be temporarily avoided. +#ifndef NDEBUG + for (unsigned i : indices(Substitutions.getReplacementTypes())) { + auto replacement = Substitutions.getReplacementTypes()[i]; + + if (!replacement->hasTypeParameter()) + continue; + + auto replacementParam = replacement->getAs(); + if (!replacementParam) + llvm_unreachable("opaque types cannot currently be parameterized by non-identity type parameter mappings"); + + assert(i == Decl->getGenericSignature()->getGenericParamOrdinal(replacementParam) + && "opaque types cannot currently be parameterized by non-identity type parameter mappings"); + } +#endif + + llvm::FoldingSetNodeID id; + Profile(id, Decl, Substitutions); + + auto &ctx = Decl->getASTContext(); + + // An opaque type isn't contextually dependent like other archetypes, so + // by itself, it doesn't impose the "Has Archetype" recursive property, + // but the substituted types might. A disjoint "Has Opaque Archetype" tracks + // the presence of opaque archetypes. + RecursiveTypeProperties properties = + RecursiveTypeProperties::HasOpaqueArchetype; + for (auto type : Substitutions.getReplacementTypes()) { + properties |= type->getRecursiveProperties(); + } + + auto arena = getArena(properties); + + llvm::FoldingSet &set + = ctx.getImpl().getArena(arena).OpaqueArchetypes; + + { + void *insertPos; // Discarded because the work below may invalidate the + // insertion point inside the folding set + if (auto existing = set.FindNodeOrInsertPos(id, insertPos)) { + return existing; + } + } + + // Create a new opaque archetype. + // It lives in an environment in which the interface generic arguments of the + // decl have all been same-type-bound to the arguments from our substitution + // map. + GenericSignatureBuilder builder(ctx); + builder.addGenericSignature(Decl->getOpaqueInterfaceGenericSignature()); + // Same-type-constrain the arguments in the outer signature to their + // replacements in the substitution map. + if (auto outerSig = Decl->getGenericSignature()) { + for (auto outerParam : outerSig->getGenericParams()) { + auto boundType = Type(outerParam).subst(Substitutions); + builder.addSameTypeRequirement(Type(outerParam), boundType, + GenericSignatureBuilder::FloatingRequirementSource::forAbstract(), + GenericSignatureBuilder::UnresolvedHandlingKind::GenerateConstraints, + [](Type, Type) { llvm_unreachable("error?"); }); + } + } + + auto signature = std::move(builder) + .computeGenericSignature(SourceLoc()); + + auto opaqueInterfaceTy = Decl->getUnderlyingInterfaceType(); + auto layout = signature->getLayoutConstraint(opaqueInterfaceTy); + auto superclass = signature->getSuperclassBound(opaqueInterfaceTy); + SmallVector protos; + for (auto proto : signature->getConformsTo(opaqueInterfaceTy)) { + protos.push_back(proto); + } + + auto mem = ctx.Allocate( + OpaqueTypeArchetypeType::totalSizeToAlloc( + protos.size(), superclass ? 1 : 0, layout ? 1 : 0), + alignof(OpaqueTypeArchetypeType), + arena); + + auto newOpaque = ::new (mem) OpaqueTypeArchetypeType(Decl, Substitutions, + properties, + opaqueInterfaceTy, + protos, superclass, layout); + + // Create a generic environment and bind the opaque archetype to the + // opaque interface type from the decl's signature. + auto env = signature->createGenericEnvironment(); + env->addMapping(GenericParamKey(opaqueInterfaceTy), newOpaque); + newOpaque->Environment = env; + + // Look up the insertion point in the folding set again in case something + // invalidated it above. + { + void *insertPos; + auto existing = set.FindNodeOrInsertPos(id, insertPos); + (void)existing; + assert(!existing && "race to create opaque archetype?!"); + set.InsertNode(newOpaque, insertPos); + } + + return newOpaque; +} + CanOpenedArchetypeType OpenedArchetypeType::get(Type existential, Optional knownID) { auto &ctx = existential->getASTContext(); @@ -5008,6 +5142,9 @@ SILLayout *SILLayout::get(ASTContext &C, CanSILBoxType SILBoxType::get(ASTContext &C, SILLayout *Layout, SubstitutionMap Substitutions) { + // TODO: Support resilient opaque types. + Substitutions = Substitutions + .substOpaqueTypesWithUnderlyingTypes(); // Canonicalize substitutions. Substitutions = Substitutions.getCanonical(); diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index cd9132c9a253d..ea18ec75c14a7 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -410,6 +410,11 @@ static void printName(raw_ostream &os, DeclName name) { os << name; } +static void dumpSubstitutionMapRec( + SubstitutionMap map, llvm::raw_ostream &out, + SubstitutionMap::DumpStyle style, unsigned indent, + llvm::SmallPtrSetImpl &visited); + namespace { class PrintPattern : public PatternVisitor { public: @@ -638,6 +643,24 @@ namespace { printInherited(TAD->getInherited()); OS << "')"; } + + void visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) { + printCommon(OTD, "opaque_type"); + OS << " naming_decl="; + printDeclName(OTD->getNamingDecl()); + PrintWithColorRAII(OS, TypeColor) << " opaque_interface=" + << Type(OTD->getUnderlyingInterfaceType()).getString(); + OS << " in " + << OTD->getOpaqueInterfaceGenericSignature()->getAsString(); + if (auto underlyingSubs = OTD->getUnderlyingTypeSubstitutions()) { + OS << " underlying:\n"; + SmallPtrSet Dumped; + dumpSubstitutionMapRec(*underlyingSubs, OS, + SubstitutionMap::DumpStyle::Full, + Indent + 2, Dumped); + } + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } void printAbstractTypeParamCommon(AbstractTypeParamDecl *decl, const char *name) { @@ -1033,6 +1056,14 @@ namespace { OS << "result\n"; printRec(FD->getBodyResultTypeLoc().getTypeRepr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; + if (auto opaque = FD->getOpaqueResultTypeDecl()) { + OS << '\n'; + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << '('; + OS << "opaque_result_decl\n"; + printRec(opaque); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } Indent -= 2; } } @@ -2169,7 +2200,11 @@ class PrintExpr : public ExprVisitor { printRec(E->getSubExpr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - + void visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E){ + printCommon(E, "underlying_to_opaque_expr") << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } void visitErasureExpr(ErasureExpr *E) { printCommon(E, "erasure_expr") << '\n'; for (auto conf : E->getConformances()) { @@ -2886,11 +2921,6 @@ static void dumpProtocolConformanceRec( unsigned indent, llvm::SmallPtrSetImpl &visited); -static void dumpSubstitutionMapRec( - SubstitutionMap map, llvm::raw_ostream &out, - SubstitutionMap::DumpStyle style, unsigned indent, - llvm::SmallPtrSetImpl &visited); - static void dumpProtocolConformanceRefRec( const ProtocolConformanceRef conformance, llvm::raw_ostream &out, unsigned indent, @@ -3414,6 +3444,20 @@ namespace { printArchetypeNestedTypes(T); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + void visitOpaqueTypeArchetypeType(OpaqueTypeArchetypeType *T, + StringRef label) { + printArchetypeCommon(T, "opaque_type", label); + printField("decl", T->getOpaqueDecl()->getNamingDecl()->printRef()); + if (!T->getSubstitutions().empty()) { + OS << '\n'; + SmallPtrSet Dumped; + dumpSubstitutionMapRec(T->getSubstitutions(), OS, + SubstitutionMap::DumpStyle::Full, + Indent + 2, Dumped); + } + printArchetypeNestedTypes(T); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } void visitGenericTypeParamType(GenericTypeParamType *T, StringRef label) { printCommon(label, "generic_type_param_type"); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 3dba06fab00c3..abd284ed303ad 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -947,6 +947,22 @@ void ASTMangler::appendType(Type type) { case TypeKind::NestedArchetype: llvm_unreachable("Cannot mangle free-standing archetypes"); + case TypeKind::OpaqueTypeArchetype: { + // TODO: Mangle opaque archetypes as themselves, not their underlying type + auto opaqueTy = cast(tybase); + + // Currently an opaque type will only lack an underlying type when in + // error. Mangle an error type for USRs and other queries that might apply + // to a failed AST. + if (!opaqueTy->getOpaqueDecl()->getUnderlyingTypeSubstitutions()) { + return appendType(ErrorType::get(opaqueTy->getASTContext())); + } + auto underlyingType = + type.substOpaqueTypesWithUnderlyingTypes(); + assert(!underlyingType->isEqual(type)); + return appendType(underlyingType->getCanonicalType()); + } + case TypeKind::DynamicSelf: { auto dynamicSelf = cast(tybase); if (dynamicSelf->getSelfType()->getAnyNominal()) { diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 2a0da223de342..1eb4956179331 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2175,6 +2175,10 @@ void PrintAST::visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) { Printer << "(\"" << PDD->getMessage()->getValue() << "\")"; } +void PrintAST::visitOpaqueTypeDecl(OpaqueTypeDecl *decl) { + // TODO: Need a parsable representation for generated interfaces. +} + void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { printDocumentationComment(decl); printAttributes(decl); @@ -4057,6 +4061,20 @@ class TypePrinter : public TypeVisitor { void visitPrimaryArchetypeType(PrimaryArchetypeType *T) { printArchetypeCommon(T); } + + void visitOpaqueTypeArchetypeType(OpaqueTypeArchetypeType *T) { + // TODO(opaque): present opaque types with user-facing syntax + Printer << "(__opaque " << T->getOpaqueDecl()->getNamingDecl()->printRef(); + if (!T->getSubstitutions().empty()) { + Printer << '<'; + auto replacements = T->getSubstitutions().getReplacementTypes(); + interleave(replacements.begin(), replacements.end(), + [&](Type t) { visit(t); }, + [&] { Printer << ", "; }); + Printer << '>'; + } + Printer << ')'; + } void visitGenericTypeParamType(GenericTypeParamType *T) { if (T->getDecl() == nullptr) { diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index 677d1401210a3..e4f44c2ac8211 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -914,6 +914,17 @@ ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Decl *decl) { // Typealiases don't introduce any other scopes. return nullptr; } + + case DeclKind::OpaqueType: { + // If we have a generic type and our parent isn't describing our + // generic parameters, build the generic parameter scope. + auto opaque = cast(decl); + if (auto scope = nextGenericParam(opaque->getGenericParams(), opaque)) + return scope; + + // Opaque type decls don't introduce any other scopes. + return nullptr; + } case DeclKind::Func: case DeclKind::Accessor: diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index e82af99ba0d2e..2bdd484bdc998 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -629,12 +629,17 @@ class Verifier : public ASTWalker { bool foundError = type->getCanonicalType().findIf([&](Type type) -> bool { if (auto archetype = type->getAs()) { + auto root = archetype->getRoot(); + + // Opaque archetypes are globally available. We don't need to check + // them here. + if (isa(root)) + return false; + // Only visit each archetype once. if (!visitedArchetypes.insert(archetype).second) return false; - auto root = archetype->getRoot(); - // We should know about archetypes corresponding to opened // existential archetypes. if (auto opened = dyn_cast(root)) { diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 07bb21dd4bca7..77dd0ca913903 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -213,6 +213,15 @@ class Traversal : public ASTVisitorgetUnderlyingTypeLoc()); } + + bool visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) { + if (OTD->getGenericParams() && + Walker.shouldWalkIntoGenericParams()) { + if (visitGenericParamList(OTD->getGenericParams())) + return true; + } + return false; + } bool visitAbstractTypeParamDecl(AbstractTypeParamDecl *TPD) { for (auto Inherit: TPD->getInherited()) { @@ -1760,6 +1769,10 @@ bool Traversal::visitOwnedTypeRepr(OwnedTypeRepr *T) { return doIt(T->getBase()); } +bool Traversal::visitOpaqueReturnTypeRepr(OpaqueReturnTypeRepr *T) { + return doIt(T->getConstraint()); +} + bool Traversal::visitFixedTypeRepr(FixedTypeRepr *T) { return false; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index a3466d93c15fa..0b277e28e734a 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -157,6 +157,7 @@ DescriptiveDeclKind Decl::getDescriptiveKind() const { TRIVIAL_KIND(Param); TRIVIAL_KIND(Module); TRIVIAL_KIND(MissingMember); + TRIVIAL_KIND(OpaqueType); case DeclKind::Enum: return cast(this)->getGenericParams() @@ -299,6 +300,7 @@ StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) { ENTRY(Module, "module"); ENTRY(MissingMember, "missing member placeholder"); ENTRY(Requirement, "requirement"); + ENTRY(OpaqueType, "opaque type"); } #undef ENTRY llvm_unreachable("bad DescriptiveDeclKind"); @@ -902,6 +904,9 @@ ImportKind ImportDecl::getBestImportKind(const ValueDecl *VD) { return ImportKind::Enum; case DeclKind::Struct: return ImportKind::Struct; + + case DeclKind::OpaqueType: + return ImportKind::Type; case DeclKind::TypeAlias: { Type type = cast(VD)->getDeclaredInterfaceType(); @@ -1991,6 +1996,7 @@ bool ValueDecl::isInstanceMember() const { case DeclKind::TypeAlias: case DeclKind::GenericTypeParam: case DeclKind::AssociatedType: + case DeclKind::OpaqueType: // Types are not instance members. return false; @@ -2313,6 +2319,22 @@ void ValueDecl::setOverriddenDecls(ArrayRef overridden) { request.cacheResult(overriddenVec); } +OpaqueTypeDecl *ValueDecl::getOpaqueResultTypeDecl() const { + if (auto func = dyn_cast(this)) { + return func->getOpaqueResultTypeDecl(); + } else { + return nullptr; + } +} + +void ValueDecl::setOpaqueResultTypeDecl(OpaqueTypeDecl *D) { + if (auto func = dyn_cast(this)) { + func->setOpaqueResultTypeDecl(D); + } else { + llvm_unreachable("decl does not support opaque result types"); + } +} + bool ValueDecl::isObjC() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, @@ -3275,9 +3297,7 @@ void TypeAliasDecl::setUnderlyingType(Type underlying) { ASTContext &ctx = getASTContext(); auto *genericSig = getGenericSignature(); - auto subs = SubstitutionMap::get( - genericSig, [&](SubstitutableType *type) -> Type { return type; }, - MakeAbstractConformanceForGenericType()); + auto subs = genericSig->getIdentitySubstitutionMap(); Type parent; auto parentDC = getDeclContext(); @@ -5726,6 +5746,21 @@ void AbstractFunctionDecl::setParameters(ParameterList *BodyParams) { BodyParams->setDeclContextOfParamDecls(this); } +OpaqueTypeDecl::OpaqueTypeDecl(ValueDecl *NamingDecl, + GenericParamList *GenericParams, + DeclContext *DC, + GenericSignature *OpaqueInterfaceGenericSignature, + GenericTypeParamType *UnderlyingInterfaceType) + : GenericTypeDecl(DeclKind::OpaqueType, DC, Identifier(), SourceLoc(), {}, + GenericParams), + NamingDecl(NamingDecl), + OpaqueInterfaceGenericSignature(OpaqueInterfaceGenericSignature), + UnderlyingInterfaceType(UnderlyingInterfaceType) +{ + // Always implicit. + setImplicit(); +} + void AbstractFunctionDecl::computeType(AnyFunctionType::ExtInfo info) { auto &ctx = getASTContext(); auto *sig = getGenericSignature(); @@ -5735,8 +5770,9 @@ void AbstractFunctionDecl::computeType(AnyFunctionType::ExtInfo info) { Type resultTy; if (auto fn = dyn_cast(this)) { resultTy = fn->getBodyResultTypeLoc().getType(); - if (!resultTy) + if (!resultTy) { resultTy = TupleType::getEmpty(ctx); + } } else if (auto ctor = dyn_cast(this)) { auto *dc = ctor->getDeclContext(); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 2d0560432802d..aea2487b223df 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -347,6 +347,7 @@ ConcreteDeclRef Expr::getReferencedDecl() const { PASS_THROUGH_REFERENCE(BridgeToObjC, getSubExpr); PASS_THROUGH_REFERENCE(BridgeFromObjC, getSubExpr); PASS_THROUGH_REFERENCE(ConditionalBridgeFromObjC, getSubExpr); + PASS_THROUGH_REFERENCE(UnderlyingToOpaque, getSubExpr); NO_REFERENCE(Coerce); NO_REFERENCE(ForcedCheckedCast); NO_REFERENCE(ConditionalCheckedCast); @@ -662,6 +663,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::ConditionalBridgeFromObjC: case ExprKind::BridgeFromObjC: case ExprKind::BridgeToObjC: + case ExprKind::UnderlyingToOpaque: // Implicit conversion nodes have no syntax of their own; defer to the // subexpression. return cast(this)->getSubExpr() diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index 6440c57ab707c..cdb315de61461 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -123,6 +123,8 @@ Type GenericEnvironment::mapTypeIntoContext(GenericEnvironment *env, Type MapTypeOutOfContext::operator()(SubstitutableType *type) const { auto archetype = cast(type); + if (isa(archetype->getRoot())) + return type; return archetype->getInterfaceType(); } diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 255c350de9ccd..76b6732317fdf 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -1029,6 +1029,14 @@ unsigned GenericParamKey::findIndexIn( return genericParams.size(); } +SubstitutionMap GenericSignature::getIdentitySubstitutionMap() const { + return SubstitutionMap::get(const_cast(this), + [](SubstitutableType *t) -> Type { + return Type(cast(t)); + }, + MakeAbstractConformanceForGenericType()); +} + unsigned GenericSignature::getGenericParamOrdinal(GenericTypeParamType *param) { return GenericParamKey(param->getDepth(), param->getIndex()) .findIndexIn(getGenericParams()); diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 5a6344b48c2e5..d4d35bd78c5fd 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -2550,6 +2550,9 @@ directReferencesForTypeRepr(Evaluator &evaluator, case TypeReprKind::Shared: case TypeReprKind::SILBox: return { }; + + case TypeReprKind::OpaqueReturn: + return { }; case TypeReprKind::Fixed: llvm_unreachable("Cannot get fixed TypeReprs in name lookup"); diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 1afedd85ab96a..5dcdbd5c843b8 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -94,18 +94,28 @@ ProtocolConformanceRef::subst(Type origType, ProtocolConformanceRef ProtocolConformanceRef::subst(Type origType, TypeSubstitutionFn subs, - LookupConformanceFn conformances) const { + LookupConformanceFn conformances, + SubstOptions options) const { if (isInvalid()) return *this; // If we have a concrete conformance, we need to substitute the // conformance to apply to the new type. if (isConcrete()) - return ProtocolConformanceRef(getConcrete()->subst(subs, conformances)); + return ProtocolConformanceRef(getConcrete()->subst(subs, conformances, + options)); + // If the type is an opaque archetype, the conformance will remain abstract, + // unless we're specifically substituting opaque types. + if (auto origArchetype = origType->getAs()) { + if (!options.contains(SubstFlags::SubstituteOpaqueArchetypes) + && isa(origArchetype->getRoot())) { + return *this; + } + } // Otherwise, compute the substituted type. auto substType = origType.subst(subs, conformances, - SubstFlags::UseErrorType); + options | SubstFlags::UseErrorType); // Opened existentials trivially conform and do not need to go through // substitution map lookup. @@ -131,6 +141,13 @@ ProtocolConformanceRef::subst(Type origType, llvm_unreachable("Invalid conformance substitution"); } +ProtocolConformanceRef +ProtocolConformanceRef::substOpaqueTypesWithUnderlyingTypes(Type origType) const { + ReplaceOpaqueTypesWithUnderlyingTypes replacer; + return subst(origType, replacer, replacer, + SubstFlags::SubstituteOpaqueArchetypes); +} + Type ProtocolConformanceRef::getTypeWitnessByName(Type type, ProtocolConformanceRef conformance, @@ -1207,7 +1224,8 @@ ProtocolConformance::subst(SubstitutionMap subMap) const { ProtocolConformance * ProtocolConformance::subst(TypeSubstitutionFn subs, - LookupConformanceFn conformances) const { + LookupConformanceFn conformances, + SubstOptions options) const { switch (getKind()) { case ProtocolConformanceKind::Normal: { auto origType = getType(); @@ -1217,7 +1235,7 @@ ProtocolConformance::subst(TypeSubstitutionFn subs, auto subMap = SubstitutionMap::get(getGenericSignature(), subs, conformances); - auto substType = origType.subst(subMap, SubstFlags::UseErrorType); + auto substType = origType.subst(subMap, options | SubstFlags::UseErrorType); if (substType->isEqual(origType)) return const_cast(this); @@ -1243,11 +1261,12 @@ ProtocolConformance::subst(TypeSubstitutionFn subs, if (origBaseType->hasTypeParameter() || origBaseType->hasArchetype()) { // Substitute into the superclass. - inheritedConformance = inheritedConformance->subst(subs, conformances); + inheritedConformance = inheritedConformance->subst(subs, conformances, + options); } auto substType = origType.subst(subs, conformances, - SubstFlags::UseErrorType); + options | SubstFlags::UseErrorType); return substType->getASTContext() .getInheritedConformance(substType, inheritedConformance); } @@ -1259,10 +1278,10 @@ ProtocolConformance::subst(TypeSubstitutionFn subs, auto origType = getType(); auto substType = origType.subst(subs, conformances, - SubstFlags::UseErrorType); + options | SubstFlags::UseErrorType); return substType->getASTContext() .getSpecializedConformance(substType, genericConformance, - subMap.subst(subs, conformances)); + subMap.subst(subs, conformances, options)); } } llvm_unreachable("bad ProtocolConformanceKind"); diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 525d5f8e143b0..a0d382251e5e4 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -310,7 +310,9 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const { // If we have an archetype, map out of the context so we can compute a // conformance access path. if (auto archetype = dyn_cast(type)) { - type = archetype->getInterfaceType()->getCanonicalType(); + if (!isa(archetype->getRoot())) { + type = archetype->getInterfaceType()->getCanonicalType(); + } } // Error path: if we don't have a type parameter, there is no conformance. @@ -444,7 +446,8 @@ SubstitutionMap SubstitutionMap::subst(SubstitutionMap subMap) const { } SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs, - LookupConformanceFn conformances) const { + LookupConformanceFn conformances, + SubstOptions options) const { if (empty()) return SubstitutionMap(); SmallVector newSubs; @@ -454,7 +457,8 @@ SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs, newSubs.push_back(Type()); continue; } - newSubs.push_back(type.subst(subs, conformances, SubstFlags::UseErrorType)); + newSubs.push_back(type.subst(subs, conformances, + options | SubstFlags::UseErrorType)); } SmallVector newConformances; @@ -474,10 +478,11 @@ SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs, conformance.getConcrete()->subst(subs, conformances))); } else { auto origType = req.getFirstType(); - auto substType = origType.subst(*this, SubstFlags::UseErrorType); + auto substType = origType.subst(*this, + options | SubstFlags::UseErrorType); newConformances.push_back( - conformance.subst(substType, subs, conformances)); + conformance.subst(substType, subs, conformances, options)); } oldConformances = oldConformances.slice(1); @@ -487,6 +492,13 @@ SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs, return SubstitutionMap(genericSig, newSubs, newConformances); } +SubstitutionMap +SubstitutionMap::substOpaqueTypesWithUnderlyingTypes() +const { + ReplaceOpaqueTypesWithUnderlyingTypes replacer; + return subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes); +} + SubstitutionMap SubstitutionMap::getProtocolSubstitutions(ProtocolDecl *protocol, Type selfType, diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 5c4e5931cd179..343f574b6d9fb 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -183,6 +183,7 @@ bool CanType::isReferenceTypeImpl(CanType type, bool functionsCount) { case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: + case TypeKind::OpaqueTypeArchetype: return cast(type)->requiresClass(); case TypeKind::Protocol: return cast(type)->requiresClass(); @@ -2376,6 +2377,9 @@ GenericEnvironment *ArchetypeType::getGenericEnvironment() const { if (auto opened = dyn_cast(root)) { return opened->getGenericEnvironment(); } + if (auto opaque = dyn_cast(root)) { + return opaque->getGenericEnvironment(); + } llvm_unreachable("unhandled root archetype kind?!"); } @@ -2426,6 +2430,114 @@ NestedArchetypeType::NestedArchetypeType(const ASTContext &Ctx, { } +OpaqueTypeArchetypeType::OpaqueTypeArchetypeType(OpaqueTypeDecl *OpaqueDecl, + SubstitutionMap Substitutions, + RecursiveTypeProperties Props, + Type InterfaceType, + ArrayRef ConformsTo, + Type Superclass, LayoutConstraint Layout) + : ArchetypeType(TypeKind::OpaqueTypeArchetype, OpaqueDecl->getASTContext(), + Props, + InterfaceType, ConformsTo, Superclass, Layout), + OpaqueDecl(OpaqueDecl), + Substitutions(Substitutions) +{ +} + +GenericSignature *OpaqueTypeArchetypeType::getBoundSignature() const { + return Environment->getGenericSignature(); +} + +static Optional> +getArchetypeAndRootOpaqueArchetype(Type maybeOpaqueType) { + auto archetype = dyn_cast(maybeOpaqueType.getPointer()); + if (!archetype) + return None; + auto opaqueRoot = dyn_cast(archetype->getRoot()); + if (!opaqueRoot) + return None; + + return std::make_pair(archetype, opaqueRoot); +} + +Type ReplaceOpaqueTypesWithUnderlyingTypes::operator()( + SubstitutableType *maybeOpaqueType) const { + auto archetypeAndRoot = getArchetypeAndRootOpaqueArchetype(maybeOpaqueType); + if (!archetypeAndRoot) + return maybeOpaqueType; + + auto archetype = archetypeAndRoot->first; + auto opaqueRoot = archetypeAndRoot->second; + auto subs = opaqueRoot->getOpaqueDecl()->getUnderlyingTypeSubstitutions(); + // TODO: Check the resilience expansion, and handle opaque types with + // unknown underlying types. For now, all opaque types are always + // fragile. + assert(subs.hasValue() && "resilient opaque types not yet supported"); + + // Apply the underlying type substitutions to the interface type of the + // archetype in question. This will map the inner generic signature of the + // opaque type to its outer signature. + auto partialSubstTy = archetype->getInterfaceType().subst(*subs); + // Then apply the substitutions from the root opaque archetype, to specialize + // for its type arguments. + auto substTy = partialSubstTy.subst(opaqueRoot->getSubstitutions()); + + // If the type still contains opaque types, recur. + if (substTy->hasOpaqueArchetype()) { + return substTy.substOpaqueTypesWithUnderlyingTypes(); + } + return substTy; +} + +Optional +ReplaceOpaqueTypesWithUnderlyingTypes::operator()(CanType maybeOpaqueType, + Type replacementType, + ProtocolDecl *protocol) const { + auto abstractRef = ProtocolConformanceRef(protocol); + + auto archetypeAndRoot = getArchetypeAndRootOpaqueArchetype(maybeOpaqueType); + if (!archetypeAndRoot) { + assert(maybeOpaqueType->isTypeParameter() + || maybeOpaqueType->is()); + return abstractRef; + } + + auto archetype = archetypeAndRoot->first; + auto opaqueRoot = archetypeAndRoot->second; + auto subs = opaqueRoot->getOpaqueDecl()->getUnderlyingTypeSubstitutions(); + assert(subs.hasValue()); + + // Apply the underlying type substitutions to the interface type of the + // archetype in question. This will map the inner generic signature of the + // opaque type to its outer signature. + auto partialSubstTy = archetype->getInterfaceType().subst(*subs); + auto partialSubstRef = abstractRef.subst(archetype->getInterfaceType(), + *subs); + + // Then apply the substitutions from the root opaque archetype, to specialize + // for its type arguments. + auto substTy = partialSubstTy.subst(opaqueRoot->getSubstitutions()); + auto substRef = partialSubstRef.subst(partialSubstTy, + opaqueRoot->getSubstitutions()); + + // If the type still contains opaque types, recur. + if (substTy->hasOpaqueArchetype()) { + return substRef.substOpaqueTypesWithUnderlyingTypes(substTy); + } + return substRef; +} + +Type Type::substOpaqueTypesWithUnderlyingTypes() const { + ReplaceOpaqueTypesWithUnderlyingTypes replacer; + return subst(replacer, replacer, + SubstFlags::SubstituteOpaqueArchetypes + // TODO(opaque): Currently lowered types always get opaque types + // substituted out of them. When we support opaque type resilience + // this won't be true anymore and we'll need to handle + // opaque type substitution in SILType::subst. + | SubstFlags::AllowLoweredTypes); +} + CanNestedArchetypeType NestedArchetypeType::getNew( const ASTContext &Ctx, ArchetypeType *Parent, @@ -2444,7 +2556,7 @@ CanNestedArchetypeType NestedArchetypeType::getNew( ConformsTo.size(), Superclass ? 1 : 0, Layout ? 1 : 0), alignof(NestedArchetypeType), arena); - return CanNestedArchetypeType(new (mem) NestedArchetypeType( + return CanNestedArchetypeType(::new (mem) NestedArchetypeType( Ctx, Parent, InterfaceType, ConformsTo, Superclass, Layout)); } @@ -2467,7 +2579,7 @@ PrimaryArchetypeType::getNew(const ASTContext &Ctx, ConformsTo.size(), Superclass ? 1 : 0, Layout ? 1 : 0), alignof(PrimaryArchetypeType), arena); - return CanPrimaryArchetypeType(new (mem) PrimaryArchetypeType( + return CanPrimaryArchetypeType(::new (mem) PrimaryArchetypeType( Ctx, GenericEnv, InterfaceType, ConformsTo, Superclass, Layout)); } @@ -2629,6 +2741,14 @@ std::string ArchetypeType::getFullName() const { return Result.str().str(); } +void +OpaqueTypeArchetypeType::Profile(llvm::FoldingSetNodeID &id, + OpaqueTypeDecl *decl, + SubstitutionMap subs) { + id.AddPointer(decl); + subs.profile(id); +} + void ProtocolCompositionType::Profile(llvm::FoldingSetNodeID &ID, ArrayRef Members, bool HasExplicitAnyObject) { @@ -2953,8 +3073,10 @@ static Type substType(Type derivedType, } // FIXME: Change getTypeOfMember() to not pass GenericFunctionType here - if (!derivedType->hasArchetype() && - !derivedType->hasTypeParameter()) + if (!derivedType->hasArchetype() + && !derivedType->hasTypeParameter() + && (!options.contains(SubstFlags::SubstituteOpaqueArchetypes) + || !derivedType->hasOpaqueArchetype())) return derivedType; return derivedType.transformRec([&](TypeBase *type) -> Optional { @@ -2995,6 +3117,11 @@ static Type substType(Type derivedType, auto substOrig = dyn_cast(type); if (!substOrig) return None; + // Opaque types can't normally be directly substituted unless we + // specifically were asked to substitute them. + if (!options.contains(SubstFlags::SubstituteOpaqueArchetypes) + && isa(substOrig)) + return None; // If we have a substitution for this type, use it. if (auto known = substitutions(substOrig)) @@ -3385,15 +3512,18 @@ Type Type::transformRec( // Recur into children of this type. TypeBase *base = getPointer(); switch (base->getKind()) { -#define ALWAYS_CANONICAL_TYPE(Id, Parent) \ +#define BUILTIN_TYPE(Id, Parent) \ case TypeKind::Id: #define TYPE(Id, Parent) #include "swift/AST/TypeNodes.def" + case TypeKind::PrimaryArchetype: + case TypeKind::OpenedArchetype: case TypeKind::Error: case TypeKind::Unresolved: case TypeKind::TypeVariable: case TypeKind::GenericTypeParam: case TypeKind::SILToken: + case TypeKind::Module: return *this; case TypeKind::Enum: @@ -3548,6 +3678,55 @@ case TypeKind::Id: return BoundGenericType::get(bound->getDecl(), substParentTy, substArgs); } + + case TypeKind::OpaqueTypeArchetype: { + auto opaque = cast(base); + if (opaque->getSubstitutions().empty()) + return *this; + + SmallVector newSubs; + bool anyChanged = false; + for (auto replacement : opaque->getSubstitutions().getReplacementTypes()) { + Type newReplacement = replacement.transformRec(fn); + if (!newReplacement) + return Type(); + newSubs.push_back(newReplacement); + if (replacement.getPointer() != newReplacement.getPointer()) + anyChanged = true; + } + + if (!anyChanged) + return *this; + + // FIXME: This re-looks-up conformances instead of transforming them in + // a systematic way. + auto sig = opaque->getOpaqueDecl()->getGenericSignature(); + auto newSubMap = + SubstitutionMap::get(sig, + [&](SubstitutableType *t) -> Type { + auto index = sig->getGenericParamOrdinal(cast(t)); + return newSubs[index]; + }, + LookUpConformanceInModule(opaque->getOpaqueDecl()->getModuleContext())); + return OpaqueTypeArchetypeType::get(opaque->getOpaqueDecl(), + newSubMap); + } + case TypeKind::NestedArchetype: { + // Transform the root type of a nested opaque archetype. + auto nestedType = cast(base); + auto root = dyn_cast(nestedType->getRoot()); + if (!root) + return *this; + + auto substRoot = Type(root).transformRec(fn); + if (substRoot.getPointer() == root) { + return *this; + } + + // Substitute the new root into the root of the interface type. + return nestedType->getInterfaceType()->substBaseType(substRoot, + LookUpConformanceInModule(root->getOpaqueDecl()->getModuleContext())); + } case TypeKind::ExistentialMetatype: { auto meta = cast(base); @@ -3999,7 +4178,8 @@ ReferenceCounting TypeBase::getReferenceCounting() { case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: - case TypeKind::NestedArchetype: { + case TypeKind::NestedArchetype: + case TypeKind::OpaqueTypeArchetype: { auto archetype = cast(type); auto layout = archetype->getLayoutConstraint(); (void)layout; diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index 8b897b79a14d9..0f3c82d4fe152 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -258,6 +258,11 @@ TypeRepr *CloneVisitor::visitSILBoxTypeRepr(SILBoxTypeRepr *type) { type->getArgumentRAngleLoc()); } +TypeRepr *CloneVisitor::visitOpaqueReturnTypeRepr(OpaqueReturnTypeRepr *type) { + return new (Ctx) OpaqueReturnTypeRepr(type->getOpaqueLoc(), + visit(type->getConstraint())); +} + TypeRepr *TypeRepr::clone(const ASTContext &ctx) const { CloneVisitor visitor(ctx); return visitor.visit(const_cast(this)); @@ -548,6 +553,11 @@ void ProtocolTypeRepr::printImpl(ASTPrinter &Printer, Printer << ".Protocol"; } +void OpaqueReturnTypeRepr::printImpl(ASTPrinter &Printer, + const PrintOptions &Opts) const { + Printer << "opaque "; + printTypeRepr(Constraint, Printer, Opts); +} void SpecifierTypeRepr::printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const { diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index 8c6ad7802e11f..ba70105096670 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -169,6 +169,19 @@ class Traversal : public TypeVisitor return false; } + + bool visitArchetypeType(ArchetypeType *ty) { + // If the root is an opaque archetype, visit its substitution replacement + // types. + if (auto opaqueRoot = dyn_cast(ty->getRoot())) { + for (auto arg : opaqueRoot->getSubstitutions().getReplacementTypes()) { + if (doIt(arg)) { + return true; + } + } + } + return false; + } bool visitTypeVariableType(TypeVariableType *ty) { return false; } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 48486e5079e49..81252eaf439ce 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -224,6 +224,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.EnableOperatorDesignatedTypes |= Args.hasArg(OPT_enable_operator_designated_types); + + Opts.EnableOpaqueResultTypes |= + Args.hasArg(OPT_enable_opaque_result_types); // Always enable operator designated types for the standard library. Opts.EnableOperatorDesignatedTypes |= FrontendOpts.ParseStdlib; diff --git a/lib/FrontendTool/ReferenceDependencies.cpp b/lib/FrontendTool/ReferenceDependencies.cpp index f4cce1d1d93f2..15e4c86f314a7 100644 --- a/lib/FrontendTool/ReferenceDependencies.cpp +++ b/lib/FrontendTool/ReferenceDependencies.cpp @@ -293,6 +293,7 @@ void ProvidesEmitter::emitTopLevelDecl(const Decl *const D, case DeclKind::Var: case DeclKind::Func: case DeclKind::Accessor: + case DeclKind::OpaqueType: emitValueDecl(cast(D)); break; diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 563c27fe9f24d..a99dd85a65204 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -486,6 +486,7 @@ CodeCompletionResult::getCodeCompletionDeclKind(const Decl *D) { case DeclKind::IfConfig: case DeclKind::PoundDiagnostic: case DeclKind::MissingMember: + case DeclKind::OpaqueType: llvm_unreachable("not expecting such a declaration result"); case DeclKind::Module: return CodeCompletionDeclKind::Module; diff --git a/lib/IRGen/Fulfillment.cpp b/lib/IRGen/Fulfillment.cpp index 285e0a6cafc7d..52fcc5b4f50eb 100644 --- a/lib/IRGen/Fulfillment.cpp +++ b/lib/IRGen/Fulfillment.cpp @@ -67,6 +67,7 @@ static bool isLeafTypeMetadata(CanType type) { case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: + case TypeKind::OpaqueTypeArchetype: case TypeKind::GenericTypeParam: case TypeKind::DependentMember: return true; diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 5d9c92bc2849b..782a998320284 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1777,6 +1777,11 @@ void IRGenModule::emitGlobalDecl(Decl *D) { case DeclKind::Module: return; + + case DeclKind::OpaqueType: + // TODO: Eventually we'll need to emit descriptors to access the opaque + // type's metadata. + return; } llvm_unreachable("bad decl kind!"); @@ -3683,6 +3688,7 @@ void IRGenModule::emitNestedTypeDecls(DeclRange members) { continue; case DeclKind::TypeAlias: + case DeclKind::OpaqueType: // Do nothing. continue; diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index f781ad6bb7f90..8370b85ec96f5 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -1458,6 +1458,18 @@ void WitnessTableBuilder::defineAssociatedTypeWitnessTableAccessFunction( AssociatedConformance requirement, CanType associatedType, ProtocolConformanceRef associatedConformance) { + // Substitute out opaque types. + auto substAssocType = associatedType + .substOpaqueTypesWithUnderlyingTypes() + ->getCanonicalType(); + if (substAssocType != associatedType) { + auto substAssocConformance = associatedConformance + .substOpaqueTypesWithUnderlyingTypes(associatedType); + + associatedType = substAssocType; + associatedConformance = substAssocConformance; + } + bool hasArchetype = associatedType->hasArchetype(); assert(isa(Conformance) && "has associated type"); diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index 4425c02ee9c9c..2ea138bfc1907 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -1773,6 +1773,9 @@ const TypeInfo *TypeConverter::convertType(CanType ty) { case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: return convertArchetypeType(cast(ty)); + case TypeKind::OpaqueTypeArchetype: + // TODO: opaque type resilience + llvm_unreachable("should be lowered to underlying type; resilience not implemented"); case TypeKind::Class: case TypeKind::Enum: case TypeKind::Struct: diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index acd37f9551c2a..1d3be2e61d4ca 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1344,6 +1344,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { case TypeKind::InOut: break; + case TypeKind::OpaqueTypeArchetype: + // TODO: opaque type resilience + llvm_unreachable("should be lowered to underlying type; resilience not implemented"); case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: { diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp index bef053624bade..583eb8ea24b45 100644 --- a/lib/Index/IndexSymbol.cpp +++ b/lib/Index/IndexSymbol.cpp @@ -158,9 +158,15 @@ SymbolInfo index::getSymbolInfoForDecl(const Decl *D) { SymbolInfo info{ SymbolKind::Unknown, SymbolSubKind::None, SymbolLanguage::Swift, SymbolPropertySet() }; switch (D->getKind()) { - case DeclKind::Enum: info.Kind = SymbolKind::Enum; break; - case DeclKind::Struct: info.Kind = SymbolKind::Struct; break; - case DeclKind::Protocol: info.Kind = SymbolKind::Protocol; break; + case DeclKind::Enum: + info.Kind = SymbolKind::Enum; + break; + case DeclKind::Struct: + info.Kind = SymbolKind::Struct; + break; + case DeclKind::Protocol: + info.Kind = SymbolKind::Protocol; + break; case DeclKind::Class: info.Kind = SymbolKind::Class; if (isUnitTestCase(cast(D))) @@ -233,6 +239,7 @@ SymbolInfo index::getSymbolInfoForDecl(const Decl *D) { case DeclKind::PoundDiagnostic: case DeclKind::MissingMember: case DeclKind::Module: + case DeclKind::OpaqueType: break; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 350ec1cb1a37d..fd64d2a7dd8e3 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2340,6 +2340,7 @@ bool Parser::parseDeclModifierList(DeclAttributes &Attributes, /// 'inout' attribute-list-clause attribute-list /// '__shared' attribute-list-clause attribute-list /// '__owned' attribute-list-clause attribute-list +/// '__opaque' attribute-list-clause attribute-list /// attribute-list-clause: /// '@' attribute /// '@' attribute attribute-list-clause diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index daf6780b9e9cf..2e99f8513d93f 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -37,8 +37,9 @@ TypeRepr *Parser::applyAttributeToType(TypeRepr *ty, VarDecl::Specifier specifier, SourceLoc specifierLoc) { // Apply those attributes that do apply. - if (!attrs.empty()) + if (!attrs.empty()) { ty = new (Context) AttributedTypeRepr(attrs, ty); + } // Apply 'inout' or '__shared' or '__owned' if (specifierLoc.isValid()) { @@ -357,8 +358,7 @@ ParserResult Parser::parseSILBoxType(GenericParamList *generics, /// attribute-list type-function /// /// type-function: -/// type-composition '->' type -/// type-composition 'throws' '->' type +/// type-composition 'throws'? '->' type /// ParserResult Parser::parseType(Diag<> MessageID, bool HandleCodeCompletion, @@ -670,19 +670,40 @@ ParserResult Parser::parseTypeIdentifier() { /// parseTypeSimpleOrComposition /// /// type-composition: -/// type-simple +/// '__opaque'? type-simple /// type-composition '&' type-simple ParserResult Parser::parseTypeSimpleOrComposition(Diag<> MessageID, bool HandleCodeCompletion) { + // Check for the opaque modifier. + // This is only semantically allowed in certain contexts, but we parse it + // generally for diagnostics and recovery. + SourceLoc opaqueLoc; + if (Context.LangOpts.EnableOpaqueResultTypes + && Tok.is(tok::identifier) + && Tok.getRawText() == "__opaque") { + opaqueLoc = consumeToken(); + } + + auto applyOpaque = [&](TypeRepr *type) -> TypeRepr* { + if (opaqueLoc.isValid()) { + type = new (Context) OpaqueReturnTypeRepr(opaqueLoc, type); + } + return type; + }; + SyntaxParsingContext CompositionContext(SyntaxContext, SyntaxContextKind::Type); // Parse the first type ParserResult FirstType = parseTypeSimple(MessageID, HandleCodeCompletion); if (FirstType.hasCodeCompletion()) return makeParserCodeCompletionResult(); - if (FirstType.isNull() || !Tok.isContextualPunctuator("&")) + if (FirstType.isNull()) return FirstType; + if (!Tok.isContextualPunctuator("&")) { + return makeParserResult(ParserStatus(FirstType), + applyOpaque(FirstType.get())); + } SmallVector Types; ParserStatus Status(FirstType); @@ -706,6 +727,20 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, assert(Tok.isContextualPunctuator("&")); do { consumeToken(); // consume '&' + + // Diagnose invalid `__opaque` after an ampersand. + if (Context.LangOpts.EnableOpaqueResultTypes + && Tok.is(tok::identifier) + && Tok.getRawText() == "__opaque") { + auto badLoc = consumeToken(); + + // TODO: Fixit to move to beginning of composition. + diagnose(badLoc, diag::opaque_mid_composition); + + if (opaqueLoc.isInvalid()) + opaqueLoc = badLoc; + } + if (SyntaxContext->isEnabled() && Status.isSuccess()) { ParsedCompositionTypeElementSyntaxBuilder Builder(*SyntaxContext); @@ -734,8 +769,8 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, } SyntaxContext->collectNodesInPlace(SyntaxKind::CompositionTypeElementList); - return makeParserResult(Status, CompositionTypeRepr::create( - Context, Types, FirstTypeLoc, {FirstAmpersandLoc, PreviousLoc})); + return makeParserResult(Status, applyOpaque(CompositionTypeRepr::create( + Context, Types, FirstTypeLoc, {FirstAmpersandLoc, PreviousLoc}))); } ParserResult diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp index 0dd10bef0088a..d95bafbe6944a 100644 --- a/lib/SIL/SILInstructions.cpp +++ b/lib/SIL/SILInstructions.cpp @@ -2125,6 +2125,14 @@ KeyPathPattern::get(SILModule &M, CanGenericSignature signature, } } + // TODO: support resilient opaque types + rootType = rootType + .substOpaqueTypesWithUnderlyingTypes() + ->getCanonicalType(); + valueType = valueType + .substOpaqueTypesWithUnderlyingTypes() + ->getCanonicalType(); + auto newPattern = KeyPathPattern::create(M, signature, rootType, valueType, components, objcString, maxOperandNo + 1); diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index 564255ead4fb0..3c04b8c1b6349 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -80,6 +80,10 @@ static bool isArchetypeValidInFunction(ArchetypeType *A, const SILFunction *F) { auto root = dyn_cast(A->getRoot()); if (!root) return true; + if (isa(A->getRoot())) + return true; + if (isa(A->getRoot())) + return true; // Ok, we have a primary archetype, make sure it is in the nested generic // environment of our caller. diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 396714652fb4c..bfc4450b632fe 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -1427,7 +1427,9 @@ const TypeLowering & TypeConverter::getTypeLowering(AbstractionPattern origType, Type origSubstType, ResilienceExpansion forExpansion) { - CanType substType = origSubstType->getCanonicalType(); + CanType substType = origSubstType->getCanonicalType() + .substOpaqueTypesWithUnderlyingTypes() + ->getCanonicalType(); auto key = getTypeKey(origType, substType); assert((!key.isDependent() || getCurGenericContext()) diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index c602795492684..a8edfeb0bfdca 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -201,6 +201,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { void visitOperatorDecl(OperatorDecl *d) {} void visitPrecedenceGroupDecl(PrecedenceGroupDecl *d) {} void visitTypeAliasDecl(TypeAliasDecl *d) {} + void visitOpaqueTypeDecl(OpaqueTypeDecl *d) {} void visitAbstractTypeParamDecl(AbstractTypeParamDecl *d) {} void visitSubscriptDecl(SubscriptDecl *d) {} void visitConstructorDecl(ConstructorDecl *d) {} diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp index ffe70bacd19bd..d7139fddfe0f2 100644 --- a/lib/SILGen/SILGenBuilder.cpp +++ b/lib/SILGen/SILGenBuilder.cpp @@ -90,10 +90,60 @@ MetatypeInst *SILGenBuilder::createMetatype(SILLocation loc, SILType metatype) { return SILBuilder::createMetatype(loc, metatype); } +/// Look through fragile opaque types to get the underlying type and +/// conformances. +static void lookThroughOpaqueTypes(CanType &concreteType) { + concreteType = concreteType + .substOpaqueTypesWithUnderlyingTypes() + ->getCanonicalType(); +} + +static void lookThroughOpaqueTypes(CanType &concreteType, + ProtocolConformanceRef &conformance) { + auto underlyingConcreteType = concreteType + .substOpaqueTypesWithUnderlyingTypes() + ->getCanonicalType(); + + if (underlyingConcreteType == concreteType) + return; + + conformance = conformance.substOpaqueTypesWithUnderlyingTypes(concreteType); + concreteType = underlyingConcreteType; +} + +static void lookThroughOpaqueTypes(CanType &concreteType, + ArrayRef &conformances) { + auto underlyingConcreteType = concreteType + .substOpaqueTypesWithUnderlyingTypes() + ->getCanonicalType(); + + if (underlyingConcreteType == concreteType) + return; + + SmallVector underlyingConformances; + bool didChangeConformances = false; + for (auto conformance : conformances) { + auto underlyingConformance = conformance + .substOpaqueTypesWithUnderlyingTypes(concreteType); + didChangeConformances |= underlyingConformance != conformance; + underlyingConformances.push_back(underlyingConformance); + } + + concreteType = underlyingConcreteType; + if (didChangeConformances) + conformances = concreteType->getASTContext() + .AllocateCopy(underlyingConformances); +} + +static void lookThroughOpaqueTypes(SubstitutionMap &subs) { + subs = subs.substOpaqueTypesWithUnderlyingTypes(); +} + ApplyInst *SILGenBuilder::createApply(SILLocation loc, SILValue fn, SILType substFnTy, SILType result, SubstitutionMap subs, ArrayRef args) { + lookThroughOpaqueTypes(subs); getSILGenModule().useConformancesFromSubstitutions(subs); return SILBuilder::createApply(loc, fn, subs, args, false); } @@ -102,6 +152,7 @@ TryApplyInst * SILGenBuilder::createTryApply(SILLocation loc, SILValue fn, SILType substFnTy, SubstitutionMap subs, ArrayRef args, SILBasicBlock *normalBB, SILBasicBlock *errorBB) { + lookThroughOpaqueTypes(subs); getSILGenModule().useConformancesFromSubstitutions(subs); return SILBuilder::createTryApply(loc, fn, subs, args, normalBB, errorBB); } @@ -110,6 +161,7 @@ BeginApplyInst * SILGenBuilder::createBeginApply(SILLocation loc, SILValue fn, SubstitutionMap subs, ArrayRef args) { + lookThroughOpaqueTypes(subs); getSILGenModule().useConformancesFromSubstitutions(subs); return SILBuilder::createBeginApply(loc, fn, subs, args, false); } @@ -118,6 +170,7 @@ PartialApplyInst * SILGenBuilder::createPartialApply(SILLocation loc, SILValue fn, SILType substFnTy, SubstitutionMap subs, ArrayRef args, SILType closureTy) { + lookThroughOpaqueTypes(subs); getSILGenModule().useConformancesFromSubstitutions(subs); return SILBuilder::createPartialApply( loc, fn, subs, args, @@ -129,6 +182,7 @@ BuiltinInst *SILGenBuilder::createBuiltin(SILLocation loc, Identifier name, SILType resultTy, SubstitutionMap subs, ArrayRef args) { + lookThroughOpaqueTypes(subs); getSILGenModule().useConformancesFromSubstitutions(subs); return SILBuilder::createBuiltin(loc, name, resultTy, subs, args); } @@ -137,9 +191,9 @@ InitExistentialAddrInst *SILGenBuilder::createInitExistentialAddr( SILLocation loc, SILValue existential, CanType formalConcreteType, SILType loweredConcreteType, ArrayRef conformances) { + lookThroughOpaqueTypes(formalConcreteType, conformances); for (auto conformance : conformances) getSILGenModule().useConformance(conformance); - return SILBuilder::createInitExistentialAddr( loc, existential, formalConcreteType, loweredConcreteType, conformances); } @@ -147,6 +201,7 @@ InitExistentialAddrInst *SILGenBuilder::createInitExistentialAddr( InitExistentialValueInst *SILGenBuilder::createInitExistentialValue( SILLocation Loc, SILType ExistentialType, CanType FormalConcreteType, SILValue Concrete, ArrayRef Conformances) { + lookThroughOpaqueTypes(FormalConcreteType, Conformances); for (auto conformance : Conformances) getSILGenModule().useConformance(conformance); @@ -156,7 +211,9 @@ InitExistentialValueInst *SILGenBuilder::createInitExistentialValue( InitExistentialMetatypeInst *SILGenBuilder::createInitExistentialMetatype( SILLocation loc, SILValue metatype, SILType existentialType, + CanType formalConcreteInstanceType, ArrayRef conformances) { + lookThroughOpaqueTypes(formalConcreteInstanceType, conformances); for (auto conformance : conformances) getSILGenModule().useConformance(conformance); @@ -167,6 +224,7 @@ InitExistentialMetatypeInst *SILGenBuilder::createInitExistentialMetatype( InitExistentialRefInst *SILGenBuilder::createInitExistentialRef( SILLocation loc, SILType existentialType, CanType formalConcreteType, SILValue concreteValue, ArrayRef conformances) { + lookThroughOpaqueTypes(formalConcreteType, conformances); for (auto conformance : conformances) getSILGenModule().useConformance(conformance); @@ -177,11 +235,78 @@ InitExistentialRefInst *SILGenBuilder::createInitExistentialRef( AllocExistentialBoxInst *SILGenBuilder::createAllocExistentialBox( SILLocation loc, SILType existentialType, CanType concreteType, ArrayRef conformances) { + lookThroughOpaqueTypes(concreteType, conformances); for (auto conformance : conformances) getSILGenModule().useConformance(conformance); return SILBuilder::createAllocExistentialBox(loc, existentialType, - concreteType, conformances); + concreteType, + conformances); +} + +DeallocExistentialBoxInst * +SILGenBuilder::createDeallocExistentialBox(SILLocation Loc, + CanType concreteType, + SILValue operand) { + lookThroughOpaqueTypes(concreteType); + return SILBuilder::createDeallocExistentialBox(Loc, concreteType, operand); +} + +UncheckedRefCastAddrInst * +SILGenBuilder::createUncheckedRefCastAddr(SILLocation Loc, + SILValue src, CanType sourceType, + SILValue dest, CanType targetType) { + lookThroughOpaqueTypes(sourceType); + lookThroughOpaqueTypes(targetType); + return SILBuilder::createUncheckedRefCastAddr(Loc, src, sourceType, + dest, targetType); +} + +UnconditionalCheckedCastAddrInst * +SILGenBuilder::createUnconditionalCheckedCastAddr(SILLocation Loc, SILValue src, + CanType sourceType, SILValue dest, + CanType targetType) { + lookThroughOpaqueTypes(sourceType); + lookThroughOpaqueTypes(targetType); + return SILBuilder::createUnconditionalCheckedCastAddr(Loc, src, sourceType, + dest, targetType); +} + +WitnessMethodInst * +SILGenBuilder::createWitnessMethod(SILLocation Loc, CanType LookupTy, + ProtocolConformanceRef Conformance, + SILDeclRef Member, SILType MethodTy) { + lookThroughOpaqueTypes(LookupTy, Conformance); + return SILBuilder::createWitnessMethod(Loc, LookupTy, Conformance, Member, + MethodTy); +} + +SILType +SILGenBuilder::getPartialApplyResultType(SILType Ty, unsigned ArgCount, + SILModule &M, + SubstitutionMap subs, + ParameterConvention calleeConvention) { + lookThroughOpaqueTypes(subs); + return SILBuilder::getPartialApplyResultType(Ty, ArgCount, M, subs, + calleeConvention); +} + +KeyPathInst * +SILGenBuilder::createKeyPath(SILLocation Loc, + KeyPathPattern *Pattern, + SubstitutionMap Subs, + ArrayRef Args, + SILType Ty) { + lookThroughOpaqueTypes(Subs); + return SILBuilder::createKeyPath(Loc, Pattern, Subs, Args, Ty); +} +InitBlockStorageHeaderInst * +SILGenBuilder::createInitBlockStorageHeader(SILLocation Loc, SILValue BlockStorage, + SILValue InvokeFunction, SILType BlockType, + SubstitutionMap Subs) { + lookThroughOpaqueTypes(Subs); + return SILBuilder::createInitBlockStorageHeader(Loc, BlockStorage, + InvokeFunction, BlockType, Subs); } //===----------------------------------------------------------------------===// @@ -241,6 +366,8 @@ ManagedValue SILGenBuilder::createConvertEscapeToNoEscape( ManagedValue SILGenBuilder::createInitExistentialValue( SILLocation loc, SILType existentialType, CanType formalConcreteType, ManagedValue concrete, ArrayRef conformances) { + lookThroughOpaqueTypes(formalConcreteType, conformances); + // *NOTE* we purposely do not use a cleanup cloner here. The reason why is no // matter whether we have a trivial or non-trivial input, // init_existential_value returns a +1 value (the COW box). @@ -253,6 +380,8 @@ ManagedValue SILGenBuilder::createInitExistentialValue( ManagedValue SILGenBuilder::createInitExistentialRef( SILLocation Loc, SILType ExistentialType, CanType FormalConcreteType, ManagedValue Concrete, ArrayRef Conformances) { + lookThroughOpaqueTypes(FormalConcreteType, Conformances); + CleanupCloner Cloner(*this, Concrete); InitExistentialRefInst *IERI = createInitExistentialRef(Loc, ExistentialType, FormalConcreteType, diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h index 1809bd0f213e8..d8cea66111092 100644 --- a/lib/SILGen/SILGenBuilder.h +++ b/lib/SILGen/SILGenBuilder.h @@ -136,6 +136,7 @@ class SILGenBuilder : public SILBuilder { InitExistentialMetatypeInst * createInitExistentialMetatype(SILLocation loc, SILValue metatype, SILType existentialType, + CanType formalConcreteInstanceType, ArrayRef conformances); InitExistentialRefInst * @@ -153,6 +154,37 @@ class SILGenBuilder : public SILBuilder { CanType concreteType, ArrayRef conformances); + // Instructions that take formal AST types need to look through fragile + // opaque archetypes. For SIL types, type lowering normally takes care of + // this. + DeallocExistentialBoxInst * + createDeallocExistentialBox(SILLocation Loc, CanType concreteType, + SILValue operand); + UncheckedRefCastAddrInst *createUncheckedRefCastAddr(SILLocation Loc, + SILValue src, CanType sourceType, + SILValue dest, CanType targetType); + UnconditionalCheckedCastAddrInst * + createUnconditionalCheckedCastAddr(SILLocation Loc, SILValue src, + CanType sourceType, SILValue dest, + CanType targetType); + WitnessMethodInst *createWitnessMethod(SILLocation Loc, CanType LookupTy, + ProtocolConformanceRef Conformance, + SILDeclRef Member, SILType MethodTy); + + static SILType getPartialApplyResultType(SILType Ty, unsigned ArgCount, + SILModule &M, + SubstitutionMap subs, + ParameterConvention calleeConvention); + KeyPathInst *createKeyPath(SILLocation Loc, + KeyPathPattern *Pattern, + SubstitutionMap Subs, + ArrayRef Args, + SILType Ty); + InitBlockStorageHeaderInst * + createInitBlockStorageHeader(SILLocation Loc, SILValue BlockStorage, + SILValue InvokeFunction, SILType BlockType, + SubstitutionMap Subs); + //===--- // Ownership Endowed APIs // diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp index 1960adf5bc8d8..af16b01f74bdc 100644 --- a/lib/SILGen/SILGenConvert.cpp +++ b/lib/SILGen/SILGenConvert.cpp @@ -775,8 +775,9 @@ ManagedValue SILGenFunction::emitExistentialErasure( auto upcast = B.createInitExistentialMetatype(loc, metatype, - existentialTL.getLoweredType(), - conformances); + existentialTL.getLoweredType(), + cast(concreteFormalType).getInstanceType(), + conformances); return ManagedValue::forUnmanaged(upcast); } case ExistentialRepresentation::Class: { diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index 3f503a4873646..c6378128566ea 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -1476,6 +1476,7 @@ void SILGenModule::emitExternalDefinition(Decl *d) { case DeclKind::PrecedenceGroup: case DeclKind::Module: case DeclKind::MissingMember: + case DeclKind::OpaqueType: llvm_unreachable("Not a valid external definition for SILGen"); } } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index aa222e13702bb..e4a263b8112b7 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -439,6 +439,7 @@ namespace { SGFContext C); RValue visitIsExpr(IsExpr *E, SGFContext C); RValue visitCoerceExpr(CoerceExpr *E, SGFContext C); + RValue visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E, SGFContext C); RValue visitTupleExpr(TupleExpr *E, SGFContext C); RValue visitMemberRefExpr(MemberRefExpr *E, SGFContext C); RValue visitDynamicMemberRefExpr(DynamicMemberRefExpr *E, SGFContext C); @@ -1916,6 +1917,12 @@ RValue RValueEmitter::visitCoerceExpr(CoerceExpr *E, SGFContext C) { return visit(E->getSubExpr(), C); } +RValue RValueEmitter::visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E, + SGFContext C) { + // TODO: For now, opaque types are always lowered to their underlying type. + return visit(E->getSubExpr(), C); +} + VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc, CanType baseTy, CanType arrayTy, unsigned numElements, diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 193d25141bae0..e5cb7b2e3ff17 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -504,7 +504,8 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { SILValue metaTy = B.createMetatype(mainClass, SILType::getPrimitiveObjectType(mainClassMetaty)); metaTy = B.createInitExistentialMetatype(mainClass, metaTy, - SILType::getPrimitiveObjectType(anyObjectMetaTy), {}); + SILType::getPrimitiveObjectType(anyObjectMetaTy), + mainClassTy, {}); SILValue optNameValue = B.createApply( mainClass, NSStringFromClass, NSStringFromClass->getType(), SILType::getPrimitiveObjectType(OptNSStringTy), {}, metaTy); diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 535064d66cdbd..06d81f767a27c 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -945,6 +945,7 @@ namespace { loc, payload, base.getType().getObjectType(), + OpenedArchetype, SGF.getASTContext().AllocateCopy(conformances)); } else { assert(getSubstFormalType()->isBridgeableObjectType()); diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 272344a525d0d..270252f975219 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -988,6 +988,7 @@ class SILGenType : public TypeMemberVisitor { // Visitors for subdeclarations //===--------------------------------------------------------------------===// void visitTypeAliasDecl(TypeAliasDecl *tad) {} + void visitOpaqueTypeDecl(OpaqueTypeDecl *otd) {} void visitAbstractTypeParamDecl(AbstractTypeParamDecl *tpd) {} void visitModuleDecl(ModuleDecl *md) {} void visitMissingMemberDecl(MissingMemberDecl *) {} @@ -1090,6 +1091,7 @@ class SILGenExtension : public TypeMemberVisitor { // Visitors for subdeclarations //===--------------------------------------------------------------------===// void visitTypeAliasDecl(TypeAliasDecl *tad) {} + void visitOpaqueTypeDecl(OpaqueTypeDecl *tad) {} void visitAbstractTypeParamDecl(AbstractTypeParamDecl *tpd) {} void visitModuleDecl(ModuleDecl *md) {} void visitMissingMemberDecl(MissingMemberDecl *) {} diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index cfdca6cef3951..c733e23264354 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -6573,6 +6573,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: + case TypeKind::OpaqueTypeArchetype: if (!cast(desugaredFromType)->requiresClass()) break; LLVM_FALLTHROUGH; @@ -6766,6 +6767,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: + case TypeKind::OpaqueTypeArchetype: case TypeKind::GenericTypeParam: case TypeKind::DependentMember: case TypeKind::Function: @@ -6780,6 +6782,12 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, return cs.cacheType(new (tc.Context) UnresolvedTypeConversionExpr(expr, toType)); + // Use an opaque type to abstract a value of the underlying concrete type. + if (toType->getAs()) { + return cs.cacheType(new (tc.Context) + UnderlyingToOpaqueExpr(expr, toType)); + } + llvm_unreachable("Unhandled coercion"); } diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index d7df12fb7e2f5..58b072827c4dc 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -475,6 +475,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) { case ConstraintKind::KeyPathApplication: case ConstraintKind::FunctionInput: case ConstraintKind::FunctionResult: + case ConstraintKind::OpaqueUnderlyingType: // Constraints from which we can't do anything. break; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index afd921bc56108..81ad53b7dbbd6 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -971,6 +971,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2, subKind = ConstraintKind::Conversion; break; + case ConstraintKind::OpaqueUnderlyingType: case ConstraintKind::Bind: case ConstraintKind::BindParam: case ConstraintKind::BindToPointerType: @@ -1033,6 +1034,7 @@ static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1, case ConstraintKind::Equal: return rep1 != rep2; + case ConstraintKind::OpaqueUnderlyingType: case ConstraintKind::Subtype: case ConstraintKind::Conversion: case ConstraintKind::BridgingConversion: @@ -1202,6 +1204,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, case ConstraintKind::Conversion: case ConstraintKind::ArgumentConversion: case ConstraintKind::OperatorArgumentConversion: + case ConstraintKind::OpaqueUnderlyingType: subKind = ConstraintKind::Subtype; break; @@ -1425,11 +1428,49 @@ ConstraintSystem::matchSuperclassTypes(Type type1, Type type2, return getTypeMatchFailure(locator); } +static ConstraintSystem::TypeMatchResult +matchDeepTypeArguments(ConstraintSystem &cs, + ConstraintSystem::TypeMatchOptions subflags, + ArrayRef args1, + ArrayRef args2, + ConstraintLocatorBuilder locator) { + if (args1.size() != args2.size()) { + return cs.getTypeMatchFailure(locator); + } + for (unsigned i = 0, n = args1.size(); i != n; ++i) { + auto result = cs.matchTypes(args1[i], args2[i], ConstraintKind::Bind, + subflags, locator.withPathElement( + LocatorPathElt::getGenericArgument(i))); + + if (result.isFailure()) + return result; + } + + return cs.getTypeMatchSuccess(); +} + ConstraintSystem::TypeMatchResult ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2, ConstraintLocatorBuilder locator) { TypeMatchOptions subflags = TMF_GenerateConstraints; + // Handle opaque archetypes. + if (auto arch1 = type1->getAs()) { + auto arch2 = type2->castTo(); + auto opaque1 = cast(arch1->getRoot()); + auto opaque2 = cast(arch2->getRoot()); + assert(arch1->getInterfaceType()->getCanonicalType( + opaque1->getGenericEnvironment()->getGenericSignature()) + == arch2->getInterfaceType()->getCanonicalType( + opaque2->getGenericEnvironment()->getGenericSignature())); + assert(opaque1->getOpaqueDecl() == opaque2->getOpaqueDecl()); + + auto args1 = opaque1->getSubstitutions().getReplacementTypes(); + auto args2 = opaque2->getSubstitutions().getReplacementTypes(); + // Match up the replacement types of the respective substitution maps. + return matchDeepTypeArguments(*this, subflags, args1, args2, locator); + } + // Handle nominal types that are not directly generic. if (auto nominal1 = type1->getAs()) { auto nominal2 = type2->castTo(); @@ -1464,19 +1505,7 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2, // Match up the generic arguments, exactly. auto args1 = bound1->getGenericArgs(); auto args2 = bound2->getGenericArgs(); - if (args1.size() != args2.size()) { - return getTypeMatchFailure(locator); - } - for (unsigned i = 0, n = args1.size(); i != n; ++i) { - auto result = matchTypes(args1[i], args2[i], ConstraintKind::Bind, - subflags, locator.withPathElement( - LocatorPathElt::getGenericArgument(i))); - - if (result.isFailure()) - return result; - } - - return getTypeMatchSuccess(); + return matchDeepTypeArguments(*this, subflags, args1, args2, locator); } ConstraintSystem::TypeMatchResult @@ -1961,6 +1990,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case ConstraintKind::OperatorArgumentConversion: return formUnsolvedResult(); + case ConstraintKind::OpaqueUnderlyingType: case ConstraintKind::ApplicableFunction: case ConstraintKind::DynamicCallableApplicableFunction: case ConstraintKind::BindOverload: @@ -2030,7 +2060,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case TypeKind::Module: case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: - case TypeKind::NestedArchetype: // If two module types or archetypes were not already equal, there's // nothing more we can do. return getTypeMatchFailure(locator); @@ -2160,6 +2189,48 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality); break; } + + // Opaque archetypes are globally bound, so we can match them for deep + // equality. + case TypeKind::OpaqueTypeArchetype: { + auto opaque1 = cast(desugar1); + auto opaque2 = cast(desugar2); + + assert(!type2->is() && "Unexpected lvalue type!"); + if (!type1->is() + && opaque1->getOpaqueDecl() == opaque2->getOpaqueDecl()) { + conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality); + } + break; + } + + // Same for nested archetypes rooted in opaque types. + case TypeKind::NestedArchetype: { + auto nested1 = cast(desugar1); + auto nested2 = cast(desugar2); + + auto rootOpaque1 = dyn_cast(nested1->getRoot()); + auto rootOpaque2 = dyn_cast(nested2->getRoot()); + if (rootOpaque1 && rootOpaque2) { + assert(!type2->is() && "Unexpected lvalue type!"); + auto interfaceTy1 = nested1->getInterfaceType() + ->getCanonicalType(rootOpaque1->getGenericEnvironment() + ->getGenericSignature()); + auto interfaceTy2 = nested2->getInterfaceType() + ->getCanonicalType(rootOpaque2->getGenericEnvironment() + ->getGenericSignature()); + if (!type1->is() + && interfaceTy1 == interfaceTy2 + && rootOpaque1->getOpaqueDecl() == rootOpaque2->getOpaqueDecl()) { + conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality); + break; + } + } + + // If the archetypes aren't rooted in an opaque type, or are rooted in + // completely different decls, then there's nothing else we can do. + return getTypeMatchFailure(locator); + } } } @@ -2739,6 +2810,7 @@ ConstraintSystem::simplifyConstructionConstraint( case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: + case TypeKind::OpaqueTypeArchetype: case TypeKind::DynamicSelf: case TypeKind::ProtocolComposition: case TypeKind::Protocol: @@ -4141,6 +4213,40 @@ ConstraintSystem::simplifyDynamicTypeOfConstraint( return SolutionKind::Error; } +ConstraintSystem::SolutionKind +ConstraintSystem::simplifyOpaqueUnderlyingTypeConstraint(Type type1, Type type2, + TypeMatchOptions flags, + ConstraintLocatorBuilder locator) { + // Open the second type, which must be an opaque archetype, to try to + // infer the first type using its constraints. + auto opaque2 = type2->castTo(); + + // Open the generic signature of the opaque decl, and bind the "outer" generic + // params to our context. The remaining axes of freedom on the type variable + // corresponding to the underlying type should be the constraints on the + // underlying return type. + OpenedTypeMap replacements; + openGeneric(nullptr, DC, opaque2->getBoundSignature(), + /*skip self*/ false, + locator, replacements); + + auto underlyingTyVar = openType(opaque2->getInterfaceType(), + replacements); + assert(underlyingTyVar); + + if (auto dcSig = DC->getGenericSignatureOfContext()) { + for (auto param : dcSig->getGenericParams()) { + addConstraint(ConstraintKind::Bind, + openType(param, replacements), + DC->mapTypeIntoContext(param), + locator); + } + } + + addConstraint(ConstraintKind::Equal, type1, underlyingTyVar, locator); + return getTypeMatchSuccess(); +} + ConstraintSystem::SolutionKind ConstraintSystem::simplifyBridgingConstraint(Type type1, Type type2, @@ -5750,6 +5856,10 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first, case ConstraintKind::OperatorArgumentConversion: return matchTypes(first, second, kind, subflags, locator); + case ConstraintKind::OpaqueUnderlyingType: + return simplifyOpaqueUnderlyingTypeConstraint(first, second, + subflags, locator); + case ConstraintKind::BridgingConversion: return simplifyBridgingConstraint(first, second, subflags, locator); @@ -6002,7 +6112,8 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { case ConstraintKind::Subtype: case ConstraintKind::Conversion: case ConstraintKind::ArgumentConversion: - case ConstraintKind::OperatorArgumentConversion: { + case ConstraintKind::OperatorArgumentConversion: + case ConstraintKind::OpaqueUnderlyingType: { // Relational constraints. auto matchKind = constraint.getKind(); diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 9151a8af880df..a3f5bcebc0643 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -1115,6 +1115,11 @@ ConstraintSystem::solveImpl(Expr *&expr, // constraint. if (convertType) { auto constraintKind = ConstraintKind::Conversion; + + if (getContextualTypePurpose() == CTP_ReturnStmt + && Options.contains(ConstraintSystemFlags::UnderlyingTypeForOpaqueReturnType)) + constraintKind = ConstraintKind::OpaqueUnderlyingType; + if (getContextualTypePurpose() == CTP_CallArgument) constraintKind = ConstraintKind::ArgumentConversion; @@ -1418,7 +1423,8 @@ void ConstraintSystem::ArgumentInfoCollector::walk(Type argType) { case ConstraintKind::ArgumentConversion: case ConstraintKind::Conversion: case ConstraintKind::BridgingConversion: - case ConstraintKind::BindParam: { + case ConstraintKind::BindParam: + case ConstraintKind::OpaqueUnderlyingType: { auto secondTy = constraint->getSecondType(); if (secondTy->is()) { auto otherRep = diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index 46b1aaaf9ff98..e38dd1b2fbc16 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -65,6 +65,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, case ConstraintKind::OptionalObject: case ConstraintKind::FunctionInput: case ConstraintKind::FunctionResult: + case ConstraintKind::OpaqueUnderlyingType: assert(!First.isNull()); assert(!Second.isNull()); break; @@ -132,6 +133,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third, case ConstraintKind::Disjunction: case ConstraintKind::FunctionInput: case ConstraintKind::FunctionResult: + case ConstraintKind::OpaqueUnderlyingType: llvm_unreachable("Wrong constructor"); case ConstraintKind::KeyPath: @@ -234,6 +236,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const { case ConstraintKind::Defaultable: case ConstraintKind::FunctionInput: case ConstraintKind::FunctionResult: + case ConstraintKind::OpaqueUnderlyingType: return create(cs, getKind(), getFirstType(), getSecondType(), getLocator()); case ConstraintKind::BindOverload: @@ -291,6 +294,7 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const { case ConstraintKind::BindToPointerType: Out << " bind to pointer "; break; case ConstraintKind::Subtype: Out << " subtype "; break; case ConstraintKind::Conversion: Out << " conv "; break; + case ConstraintKind::OpaqueUnderlyingType: Out << " underlying type of opaque "; break; case ConstraintKind::BridgingConversion: Out << " bridging conv "; break; case ConstraintKind::ArgumentConversion: Out << " arg conv "; break; case ConstraintKind::OperatorArgumentConversion: @@ -511,6 +515,7 @@ gatherReferencedTypeVars(Constraint *constraint, case ConstraintKind::SelfObjectOfProtocol: case ConstraintKind::FunctionInput: case ConstraintKind::FunctionResult: + case ConstraintKind::OpaqueUnderlyingType: constraint->getFirstType()->getTypeVariables(typeVars); constraint->getSecondType()->getTypeVariables(typeVars); break; diff --git a/lib/Sema/Constraint.h b/lib/Sema/Constraint.h index d864faa91b210..6d51ab9261c6d 100644 --- a/lib/Sema/Constraint.h +++ b/lib/Sema/Constraint.h @@ -132,14 +132,14 @@ enum class ConstraintKind : char { /// an existential). OpenedExistentialOf, /// A relation between three types. The first is the key path type, - // the second is the root type, and the third is the projected value type. - // The second and third types can be lvalues depending on the kind of key - // path. + /// the second is the root type, and the third is the projected value type. + /// The second and third types can be lvalues depending on the kind of key + /// path. KeyPathApplication, /// A relation between three types. The first is the key path type, - // the second is its root type, and the third is the projected value type. - // The key path type is chosen based on the selection of overloads for the - // member references along the path. + /// the second is its root type, and the third is the projected value type. + /// The key path type is chosen based on the selection of overloads for the + /// member references along the path. KeyPath, /// The first type is a function type, the second is the function's /// input type. @@ -147,6 +147,9 @@ enum class ConstraintKind : char { /// The first type is a function type, the second is the function's /// result type. FunctionResult, + /// The first type is a type that's a candidate to be the underlying type of + /// the second opaque archetype. + OpaqueUnderlyingType, }; /// Classification of the different kinds of constraints. @@ -477,6 +480,7 @@ class Constraint final : public llvm::ilist_node, case ConstraintKind::DynamicCallableApplicableFunction: case ConstraintKind::BindOverload: case ConstraintKind::OptionalObject: + case ConstraintKind::OpaqueUnderlyingType: return ConstraintClassification::Relational; case ConstraintKind::ValueMember: diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index ae277f6d226b8..669d7272419d2 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -816,6 +816,10 @@ enum class ConstraintSystemFlags { /// If set, constraint system always reuses type of pre-typechecked /// expression, and doesn't dig into its subexpressions. ReusePrecheckedType = 0x20, + + /// If set, the top-level expression may be able to provide an underlying + /// type for the contextual opaque archetype. + UnderlyingTypeForOpaqueReturnType = 0x40, }; /// Options that affect the constraint system as a whole. @@ -2711,6 +2715,12 @@ class ConstraintSystem { TypeMatchOptions flags, ConstraintLocatorBuilder locator); + /// Attempt to simplify an OpaqueUnderlyingType constraint. + SolutionKind simplifyOpaqueUnderlyingTypeConstraint(Type type1, + Type type2, + TypeMatchOptions flags, + ConstraintLocatorBuilder locator); + /// Attempt to simplify the BridgingConversion constraint. SolutionKind simplifyBridgingConstraint(Type type1, Type type2, diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index 1ed2d1885c349..02f03b34a37a9 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -285,6 +285,7 @@ static void doDynamicLookup(VisibleDeclConsumer &Consumer, case DeclKind::Class: case DeclKind::Struct: case DeclKind::Protocol: + case DeclKind::OpaqueType: return; // Initializers cannot be found by dynamic lookup. diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index bc93fbaf2c10f..1ee8db7fddf28 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -2434,9 +2434,109 @@ class VarDeclUsageChecker : public ASTWalker { } }; + +/// An AST walker that determines the underlying type of an opaque return decl +/// from its associated function body. +class OpaqueUnderlyingTypeChecker : public ASTWalker { + TypeChecker &TC; + AbstractFunctionDecl *Implementation; + OpaqueTypeDecl *OpaqueDecl; + SmallVector, 4> Candidates; +public: + OpaqueUnderlyingTypeChecker(TypeChecker &TC, + AbstractFunctionDecl *Implementation, + OpaqueTypeDecl *OpaqueDecl) + : TC(TC), + Implementation(Implementation), + OpaqueDecl(OpaqueDecl) + { + + } + + void check() { + Implementation->getBody()->walk(*this); + + // If there are no candidates, then the body has no return statements, and + // we have nothing to infer the underlying type from. + if (Candidates.empty()) { + TC.diagnose(Implementation->getLoc(), + diag::opaque_type_no_underlying_type_candidates); + return; + } + + // Check whether all of the underlying type candidates match up. + auto opaqueTypeInContext = + Implementation->mapTypeIntoContext(OpaqueDecl->getDeclaredInterfaceType()); + Type underlyingType = Candidates.front().second; + + bool mismatch = false; + for (auto otherCandidate : llvm::makeArrayRef(Candidates).slice(1)) { + // Disregard tautological candidates. + if (otherCandidate.second->isEqual(opaqueTypeInContext)) + continue; + + if (!underlyingType->isEqual(otherCandidate.second)) { + mismatch = true; + break; + } + } + + if (mismatch) { + TC.diagnose(Implementation->getLoc(), + diag::opaque_type_mismatched_underlying_type_candidates); + for (auto candidate : Candidates) { + TC.diagnose(candidate.first->getLoc(), + diag::opaque_type_underlying_type_candidate_here, + candidate.second); + } + return; + } + + // The underlying type can't be defined recursively + // in terms of the opaque type itself. + auto isSelfReferencing = underlyingType.findIf([&](Type t) -> bool { + return t->isEqual(opaqueTypeInContext); + }); + + if (isSelfReferencing) { + TC.diagnose(Candidates.front().first->getLoc(), + diag::opaque_type_self_referential_underlying_type, + underlyingType); + return; + } + + // If we have one successful candidate, then save it as the underlying type + // of the opaque decl. + // Form a substitution map that defines it in terms of the other context + // generic parameters. + underlyingType = underlyingType->mapTypeOutOfContext(); + auto underlyingSubs = SubstitutionMap::get( + OpaqueDecl->getOpaqueInterfaceGenericSignature(), + [&](SubstitutableType *t) -> Type { + if (t->isEqual(OpaqueDecl->getUnderlyingInterfaceType())) { + return underlyingType; + } + return Type(t); + }, + LookUpConformanceInModule(OpaqueDecl->getModuleContext())); + + OpaqueDecl->setUnderlyingTypeSubstitutions(underlyingSubs); + } + + std::pair walkToExprPre(Expr *E) override { + if (auto underlyingToOpaque = dyn_cast(E)) { + assert(E->getType()->isEqual( + Implementation->mapTypeIntoContext(OpaqueDecl->getDeclaredInterfaceType())) + && "unexpected opaque type in function body"); + + Candidates.push_back(std::make_pair(underlyingToOpaque->getSubExpr(), + underlyingToOpaque->getSubExpr()->getType())); + } + return std::make_pair(false, E); + } +}; } // end anonymous namespace - // After we have scanned the entire region, diagnose variables that could be // declared with a narrower usage kind. VarDeclUsageChecker::~VarDeclUsageChecker() { @@ -2863,6 +2963,12 @@ void swift::performAbstractFuncDeclDiagnostics(TypeChecker &TC, // Check for unused variables, as well as variables that are could be // declared as constants. AFD->getBody()->walk(VarDeclUsageChecker(TC, AFD)); + + // If the function has an opaque return type, check the return expressions + // to determine the underlying type. + if (auto opaqueResultTy = AFD->getOpaqueResultTypeDecl()) { + OpaqueUnderlyingTypeChecker(TC, AFD, opaqueResultTy).check(); + } } // Perform MiscDiagnostics on Switch Statements. diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 59f13d7a3856c..8f7be80c8c50b 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -556,6 +556,11 @@ class AccessControlChecker : public AccessControlCheckerBase, highlightOffendingType(TC, diag, complainRepr); }); } + + void visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) { + // TODO(opaque): The constraint class/protocols on the opaque interface, as + // well as the naming decl for the opaque type, need to be accessible. + } void visitAssociatedTypeDecl(AssociatedTypeDecl *assocType) { // This must stay in sync with diag::associated_type_access. @@ -1132,6 +1137,11 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, }); } + void visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) { + // TODO(opaque): The constraint class/protocols on the opaque interface, as + // well as the naming decl for the opaque type, need to be accessible. + } + void visitAssociatedTypeDecl(AssociatedTypeDecl *assocType) { // This must stay in sync with diag::associated_type_not_usable_from_inline. enum { diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index dd9cdcd38a92c..4e04fe962004f 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2066,6 +2066,9 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, if (options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables)) csOptions |= ConstraintSystemFlags::AllowUnresolvedTypeVariables; + if (options.contains(TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType)) + csOptions |= ConstraintSystemFlags::UnderlyingTypeForOpaqueReturnType; + ConstraintSystem cs(*this, dc, csOptions, expr); cs.baseCS = baseCS; @@ -2952,9 +2955,13 @@ static Type replaceArchetypesWithTypeVariables(ConstraintSystem &cs, if (auto archetypeType = dyn_cast(origType)) { auto root = archetypeType->getRoot(); + // We leave opaque types and their nested associated types alone here. + // They're globally available. + if (isa(root)) + return origType; // For other nested types, fail here so the default logic in subst() // for nested types applies. - if (root != archetypeType) + else if (root != archetypeType) return Type(); auto locator = cs.getConstraintLocator(nullptr); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 445aa41a4ce99..685ed8cbce1dd 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1010,6 +1010,15 @@ static void validatePatternBindingEntry(TypeChecker &tc, if (!pattern->hasType() || pattern->getType()->hasUnboundGenericType()) { if (tc.typeCheckPatternBinding(binding, entryNumber)) return; + + // A pattern binding at top level is not allowed to pick up another decl's + // opaque result type as its type by type inference. + if (!binding->getDeclContext()->isLocalContext() + && binding->getInit(entryNumber)->getType()->hasOpaqueArchetype()) { + // TODO: Check whether the type is the pattern binding's own opaque type. + tc.diagnose(binding, diag::inferred_opaque_type, + binding->getInit(entryNumber)->getType()); + } } // If the pattern binding appears in a type or library file context, then @@ -2454,6 +2463,15 @@ class DeclChecker : public DeclVisitor { checkAccessControl(TC, TAD); } + void visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) { + TC.checkDeclAttributesEarly(OTD); + + TC.validateDecl(OTD); + TC.checkDeclAttributes(OTD); + + checkAccessControl(TC, OTD); + } + void visitAssociatedTypeDecl(AssociatedTypeDecl *AT) { TC.checkDeclAttributesEarly(AT); @@ -3632,6 +3650,13 @@ void TypeChecker::validateDecl(ValueDecl *D) { validateTypealiasType(*this, typeAlias); break; } + + case DeclKind::OpaqueType: { + auto opaque = cast(D); + DeclValidationRAII IBV(opaque); + validateGenericTypeSignature(opaque); + break; + } case DeclKind::Enum: case DeclKind::Struct: @@ -3995,6 +4020,12 @@ void TypeChecker::validateDecl(ValueDecl *D) { } checkDeclAttributes(FD); + + // FIXME: For now, functions with opaque result types have to have their + // bodies type checked to get the underlying type. + if (FD->getOpaqueResultTypeDecl()) + typeCheckDecl(FD); + break; } @@ -4572,12 +4603,7 @@ static Type formExtensionInterfaceType( auto typealiasSig = typealias->getGenericSignature(); SubstitutionMap subMap; if (typealiasSig) { - subMap = SubstitutionMap::get( - typealiasSig, - [](SubstitutableType *type) -> Type { - return Type(type); - }, - MakeAbstractConformanceForGenericType()); + subMap = typealiasSig->getIdentitySubstitutionMap(); mustInferRequirements = true; } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 47492882c10d1..1ec9cc0a290b2 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "TypeChecker.h" #include "TypeCheckType.h" +#include "swift/AST/ExistentialLayout.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignatureBuilder.h" #include "swift/AST/ProtocolConformance.h" @@ -170,6 +171,113 @@ static void revertDependentTypeLoc(TypeLoc &tl) { /// Generic functions /// +/// Get the opaque type representing the return type of a declaration, or +/// create it if it does not yet exist. +static Type getOpaqueResultType(TypeChecker &tc, + TypeResolution resolution, + ValueDecl *originatingDecl, + OpaqueReturnTypeRepr *repr) { + // If the decl already has an opaque type decl for its return type, use it. + if (auto existingDecl = originatingDecl->getOpaqueResultTypeDecl()) { + return existingDecl->getDeclaredInterfaceType(); + } + + // Try to resolve the constraint repr. It should be some kind of existential + // type. + TypeResolutionOptions options(TypeResolverContext::GenericRequirement); + TypeLoc constraintTypeLoc(repr->getConstraint()); + // Pass along the error type if resolving the repr failed. + bool validationError + = tc.validateType(constraintTypeLoc, resolution, options); + auto constraintType = constraintTypeLoc.getType(); + if (validationError) + return constraintType; + + // Error out if the constraint type isn't a class or existential type. + if (!constraintType->getClassOrBoundGenericClass() + && !constraintType->isExistentialType()) { + tc.diagnose(repr->getConstraint()->getLoc(), + diag::opaque_type_invalid_constraint); + return constraintTypeLoc.getType(); + } + + // Create a generic signature for the opaque environment. This is the outer + // generic signature with an added generic parameter representing the opaque + // type and its interface constraints. + SmallVector interfaceGenericParams; + SmallVector interfaceRequirements; + + auto originatingDC = originatingDecl->getInnermostDeclContext(); + auto outerGenericSignature = originatingDC->getGenericSignatureOfContext(); + if (outerGenericSignature) { + std::copy(outerGenericSignature->getGenericParams().begin(), + outerGenericSignature->getGenericParams().end(), + std::back_inserter(interfaceGenericParams)); + std::copy(outerGenericSignature->getRequirements().begin(), + outerGenericSignature->getRequirements().end(), + std::back_inserter(interfaceRequirements)); + } + + unsigned returnTypeDepth = 0; + if (!interfaceGenericParams.empty()) + returnTypeDepth = interfaceGenericParams.back()->getDepth() + 1; + auto returnTypeParam = GenericTypeParamType::get(returnTypeDepth, 0, + tc.Context); + interfaceGenericParams.push_back(returnTypeParam); + + if (constraintType->getClassOrBoundGenericClass()) { + // Use the type as a superclass constraint. + interfaceRequirements.push_back(Requirement(RequirementKind::Superclass, + returnTypeParam, constraintType)); + } else { + auto constraints = constraintType->getExistentialLayout(); + if (auto superclass = constraints.getSuperclass()) { + interfaceRequirements.push_back(Requirement(RequirementKind::Superclass, + returnTypeParam, superclass)); + } + for (auto protocol : constraints.getProtocols()) { + interfaceRequirements.push_back(Requirement(RequirementKind::Conformance, + returnTypeParam, protocol)); + } + if (auto layout = constraints.getLayoutConstraint()) { + interfaceRequirements.push_back(Requirement(RequirementKind::Layout, + returnTypeParam, layout)); + } + } + + auto interfaceSignature = GenericSignature::get(interfaceGenericParams, + interfaceRequirements); + + // Create the OpaqueTypeDecl for the result type. + // It has the same parent context and generic environment as the originating + // decl. + auto dc = originatingDecl->getDeclContext(); + // TODO: generalize + auto genericParams = cast(originatingDecl)->getGenericParams(); + + auto opaqueDecl = new (tc.Context) OpaqueTypeDecl(originatingDecl, + genericParams, + dc, + interfaceSignature, + returnTypeParam); + opaqueDecl->copyFormalAccessFrom(originatingDecl); + if (auto originatingEnv = originatingDC->getGenericEnvironmentOfContext()) { + opaqueDecl->setGenericEnvironment(originatingEnv); + } + + originatingDecl->setOpaqueResultTypeDecl(opaqueDecl); + + // The declared interface type is an opaque ArchetypeType. + SubstitutionMap subs; + if (outerGenericSignature) { + subs = outerGenericSignature->getIdentitySubstitutionMap(); + } + auto opaqueTy = OpaqueTypeArchetypeType::get(opaqueDecl, subs); + auto metatype = MetatypeType::get(opaqueTy); + opaqueDecl->setInterfaceType(metatype); + return opaqueTy; +} + /// Check the signature of a generic function. static void checkGenericFuncSignature(TypeChecker &tc, GenericSignatureBuilder *builder, @@ -196,13 +304,26 @@ static void checkGenericFuncSignature(TypeChecker &tc, // If there is a declared result type, check that as well. if (auto fn = dyn_cast(func)) { - if (!fn->getBodyResultTypeLoc().isNull()) { + auto &resultTypeLoc = fn->getBodyResultTypeLoc(); + if (!resultTypeLoc.isNull()) { // Check the result type of the function. - TypeResolutionOptions options(fn->hasDynamicSelf() - ? TypeResolverContext::DynamicSelfResult - : TypeResolverContext::FunctionResult); + // It is allowed to be an opaque result type. Create the decl and type + // for it if necessary. + if (auto opaqueType = dyn_cast_or_null( + resultTypeLoc.getTypeRepr())) { + // We don't need to create the opaque type right away for structural + // checking. + if (resolution.getStage() != TypeResolutionStage::Structural) { + resultTypeLoc.setType( + getOpaqueResultType(tc, resolution, fn, opaqueType)); + } + } else { + TypeResolutionOptions options(fn->hasDynamicSelf() + ? TypeResolverContext::DynamicSelfResult + : TypeResolverContext::FunctionResult); - tc.validateType(fn->getBodyResultTypeLoc(), resolution, options); + tc.validateType(resultTypeLoc, resolution, options); + } // Infer requirements from it. if (builder && @@ -498,7 +619,7 @@ computeGenericFuncSignature(TypeChecker &tc, AbstractFunctionDecl *func) { // The generic signature builder now has all of the requirements, although // there might still be errors that have not yet been diagnosed. Revert the - // generic function signature and type-check it again, completely. + // generic function signature and type-check the function again, completely. revertGenericFuncSignature(func); // Debugging of the generic signature. diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 494e5cade05fb..a0ccd10ef32b1 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -437,7 +437,7 @@ class StmtChecker : public StmtVisitor { // In an initializer, the only expression allowed is "nil", which indicates // failure from a failable initializer. if (auto ctor = dyn_cast_or_null( - TheFunc->getAbstractFunctionDecl())) { + TheFunc->getAbstractFunctionDecl())) { // The only valid return expression in an initializer is the literal // 'nil'. auto nilExpr = dyn_cast(E->getSemanticsProvidingExpr()); @@ -463,9 +463,23 @@ class StmtChecker : public StmtVisitor { return new (TC.Context) FailStmt(RS->getReturnLoc(), nilExpr->getLoc(), RS->isImplicit()); } + + TypeCheckExprOptions options = {}; + + // If the result type is an opaque type, this is an opportunity to resolve + // the underlying type. + if (auto opaque = ResultTy->getAs()) { + if (auto funcDecl = TheFunc->getAbstractFunctionDecl()) { + if (opaque->getOpaqueDecl()->getNamingDecl() == funcDecl) { + options |= TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType; + } + } + } auto exprTy = TC.typeCheckExpression(E, DC, TypeLoc::withoutLoc(ResultTy), - CTP_ReturnStmt); + CTP_ReturnStmt, + options); + RS->setResult(E); if (!exprTy) { diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index a61611f8d96a7..e7eca0f585d03 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1920,6 +1920,24 @@ Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) { case TypeReprKind::Protocol: return resolveProtocolType(cast(repr), options); + + case TypeReprKind::OpaqueReturn: { + // Only valid as the return type of a function, which should be handled + // during function decl type checking. + auto opaqueRepr = cast(repr); + if (!(options & TypeResolutionFlags::SilenceErrors)) { + diagnose(opaqueRepr->getOpaqueLoc(), + diag::unsupported_opaque_type); + } + + // Try to resolve the constraint upper bound type as a placeholder. + options |= TypeResolutionFlags::SilenceErrors; + auto constraintType = resolveType(opaqueRepr->getConstraint(), + options); + + return constraintType && !constraintType->hasError() + ? ErrorType::get(constraintType) : ErrorType::get(Context); + } case TypeReprKind::Fixed: return cast(repr)->getType(); @@ -3317,6 +3335,10 @@ class UnsupportedProtocolVisitor visit(compound->getComponentRange().back()); return false; } + // Arbitrary protocol constraints are OK on opaque types. + if (isa(T)) + return false; + visit(T); return true; } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index b9b030cc1321b..67dd30edc0fcc 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -271,6 +271,13 @@ enum class TypeCheckExprFlags { /// as part of the expression diagnostics, which is attempting to narrow /// down failure location. SubExpressionDiagnostics = 0x400, + + /// If set, the 'convertType' specified to typeCheckExpression is the opaque + /// return type of the declaration being checked. The archetype should be + /// opened into a type variable to provide context to the expression, and + /// the resulting type will be a candidate for binding the underlying + /// type. + ConvertTypeIsOpaqueReturnType = 0x800, }; using TypeCheckExprOptions = OptionSet; diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 2a8521ce6d76b..a0cb9d7a885d1 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2830,6 +2830,7 @@ class swift::DeclDeserializer { DeclID accessorStorageDeclID; bool needsNewVTableEntry; uint8_t rawDefaultArgumentResilienceExpansion; + DeclID opaqueResultTypeDeclID; ArrayRef nameAndDependencyIDs; if (!isAccessor) { @@ -2844,6 +2845,7 @@ class swift::DeclDeserializer { rawAccessLevel, needsNewVTableEntry, rawDefaultArgumentResilienceExpansion, + opaqueResultTypeDeclID, nameAndDependencyIDs); } else { decls_block::AccessorLayout::readRecord(scratch, contextID, isImplicit, @@ -3028,6 +3030,10 @@ class swift::DeclDeserializer { return nullptr; } + if (opaqueResultTypeDeclID) + fn->setOpaqueResultTypeDecl( + cast(MF.getDecl(opaqueResultTypeDeclID))); + // Set the interface type. fn->computeType(); @@ -3042,6 +3048,42 @@ class swift::DeclDeserializer { StringRef blobData) { return deserializeAnyFunc(scratch, blobData, /*isAccessor*/true); } + + Expected deserializeOpaqueType(ArrayRef scratch, + StringRef blobData) { + DeclID namingDeclID; + DeclContextID contextID; + GenericSignatureID interfaceSigID; + TypeID interfaceTypeID; + GenericEnvironmentID genericEnvID; + SubstitutionMapID underlyingTypeID; + + decls_block::OpaqueTypeLayout::readRecord(scratch, contextID, + namingDeclID, interfaceSigID, + interfaceTypeID, genericEnvID, + underlyingTypeID); + + auto opaqueDecl = + new (ctx) OpaqueTypeDecl(cast(MF.getDecl(namingDeclID)), + nullptr, + MF.getDeclContext(contextID), + MF.getGenericSignature(interfaceSigID), + MF.getType(interfaceTypeID)->castTo()); + auto genericEnv = MF.getGenericEnvironment(genericEnvID); + opaqueDecl->setGenericEnvironment(genericEnv); + if (underlyingTypeID) + opaqueDecl->setUnderlyingTypeSubstitutions( + MF.getSubstitutionMap(underlyingTypeID)); + SubstitutionMap subs; + if (genericEnv) { + subs = genericEnv->getGenericSignature()->getIdentitySubstitutionMap(); + } + auto opaqueTy = OpaqueTypeArchetypeType::get(opaqueDecl, subs); + auto metatype = MetatypeType::get(opaqueTy); + opaqueDecl->setInterfaceType(metatype); + + return opaqueDecl; + } Expected deserializePatternBinding(ArrayRef scratch, StringRef blobData) { @@ -4097,6 +4139,7 @@ DeclDeserializer::getDeclCheckedImpl() { CASE(Var) CASE(Param) CASE(Func) + CASE(OpaqueType) CASE(Accessor) CASE(PatternBinding) CASE(Protocol) @@ -4683,6 +4726,18 @@ class swift::TypeDeserializer { return OpenedArchetypeType::get(MF.getType(existentialID)); } + Expected deserializeOpaqueArchetypeType(ArrayRef scratch, + StringRef blobData) { + DeclID opaqueDeclID; + SubstitutionMapID subsID; + decls_block::OpaqueArchetypeTypeLayout::readRecord(scratch, + opaqueDeclID, subsID); + auto opaqueDecl = cast(MF.getDecl(opaqueDeclID)); + auto subs = MF.getSubstitutionMap(subsID); + + return Type(OpaqueTypeArchetypeType::get(opaqueDecl, subs)); + } + Expected deserializeNestedArchetypeType(ArrayRef scratch, StringRef blobData) { TypeID rootID, interfaceTyID; @@ -5114,6 +5169,7 @@ Expected TypeDeserializer::getTypeCheckedImpl() { CASE(ReferenceStorage) CASE(PrimaryArchetype) CASE(OpenedArchetype) + CASE(OpaqueArchetype) CASE(NestedArchetype) CASE(GenericTypeParam) CASE(ProtocolComposition) diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 6b009368bc53f..2f3e33c081055 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1745,6 +1745,9 @@ static bool shouldSerializeMember(Decl *D) { case DeclKind::EnumCase: return false; + case DeclKind::OpaqueType: + return true; + case DeclKind::EnumElement: case DeclKind::Protocol: case DeclKind::Constructor: @@ -3314,6 +3317,7 @@ void Serializer::writeDecl(const Decl *D) { rawAccessLevel, fn->needsNewVTableEntry(), rawDefaultArgumentResilienceExpansion, + addDeclRef(fn->getOpaqueResultTypeDecl()), nameComponentsAndDependencies); writeGenericParams(fn->getGenericParams()); @@ -3329,6 +3333,31 @@ void Serializer::writeDecl(const Decl *D) { break; } + case DeclKind::OpaqueType: { + auto opaqueDecl = cast(D); + verifyAttrSerializable(opaqueDecl); + + auto namingDeclID = addDeclRef(opaqueDecl->getNamingDecl()); + auto contextID = addDeclContextRef(opaqueDecl->getDeclContext()); + auto interfaceSigID = + addGenericSignatureRef(opaqueDecl->getOpaqueInterfaceGenericSignature()); + auto interfaceTypeID = + addTypeRef(opaqueDecl->getUnderlyingInterfaceType()); + + auto genericEnvID = addGenericEnvironmentRef(opaqueDecl->getGenericEnvironment()); + + SubstitutionMapID underlyingTypeID = 0; + if (auto underlying = opaqueDecl->getUnderlyingTypeSubstitutions()) + underlyingTypeID = addSubstitutionMapRef(*underlying); + + unsigned abbrCode = DeclTypeAbbrCodes[OpaqueTypeLayout::Code]; + OpaqueTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, + contextID, namingDeclID, interfaceSigID, + interfaceTypeID, genericEnvID, + underlyingTypeID); + break; + } + case DeclKind::Accessor: { auto fn = cast(D); verifyAttrSerializable(fn); @@ -3843,6 +3872,15 @@ void Serializer::writeType(Type ty) { break; } + case TypeKind::OpaqueTypeArchetype: { + auto archetypeTy = cast(ty.getPointer()); + auto declID = addDeclRef(archetypeTy->getOpaqueDecl()); + auto substMapID = addSubstitutionMapRef(archetypeTy->getSubstitutions()); + unsigned abbrCode = DeclTypeAbbrCodes[OpaqueArchetypeTypeLayout::Code]; + OpaqueArchetypeTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, + declID, substMapID); + break; + } case TypeKind::NestedArchetype: { auto archetypeTy = cast(ty.getPointer()); auto rootTypeID = addTypeRef(archetypeTy->getRoot()); @@ -4109,6 +4147,7 @@ void Serializer::writeAllDeclsAndTypes() { registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); + registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); @@ -4132,6 +4171,7 @@ void Serializer::writeAllDeclsAndTypes() { registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); + registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index f941f5e8d65d7..7e7261be08516 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -464,6 +464,7 @@ static bool isValidProtocolMemberForTBDGen(const Decl *D) { case DeclKind::IfConfig: case DeclKind::PoundDiagnostic: return true; + case DeclKind::OpaqueType: case DeclKind::Enum: case DeclKind::Struct: case DeclKind::Class: diff --git a/test/Serialization/Inputs/OpaqueCrossFileB.swift b/test/Serialization/Inputs/OpaqueCrossFileB.swift new file mode 100644 index 0000000000000..f8dcc2cade600 --- /dev/null +++ b/test/Serialization/Inputs/OpaqueCrossFileB.swift @@ -0,0 +1,9 @@ +public protocol Foo {} + +public struct FooImpl: Foo { + public init() {} +} + +public func anyFoo() -> __opaque Foo { + return FooImpl() +} diff --git a/test/Serialization/opaque_cross_file.swift b/test/Serialization/opaque_cross_file.swift new file mode 100644 index 0000000000000..24d75c02593bf --- /dev/null +++ b/test/Serialization/opaque_cross_file.swift @@ -0,0 +1,8 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module-path %t/OpaqueCrossFileB.swiftmodule -module-name OpaqueCrossFileB %S/Inputs/OpaqueCrossFileB.swift +// RUN: %target-swift-frontend -I %t -emit-ir -verify %s + +import OpaqueCrossFileB + +dump(anyFoo()) + diff --git a/test/type/opaque.swift b/test/type/opaque.swift new file mode 100644 index 0000000000000..864438d7e6f69 --- /dev/null +++ b/test/type/opaque.swift @@ -0,0 +1,256 @@ +// RUN: %target-swift-frontend -typecheck -verify -enable-opaque-result-types %s + +protocol P { + func paul() + mutating func priscilla() +} +protocol Q { func quinn() } +extension Int: P, Q { func paul() {}; mutating func priscilla() {}; func quinn() {} } +extension String: P, Q { func paul() {}; mutating func priscilla() {}; func quinn() {} } +extension Array: P, Q { func paul() {}; mutating func priscilla() {}; func quinn() {} } + +class C {} +class D: C, P, Q { func paul() {}; func priscilla() {}; func quinn() {} } + +// TODO: Should be valid + +let foo: __opaque P = 1 // FIXME expected-error{{'opaque' types are only implemented}} +var computedFoo: __opaque P { // FIXME expected-error{{'opaque' types are only implemented}} + get { return 1 } + set { _ = newValue + 1 } +} +struct SubscriptTest { + subscript(_ x: Int) -> __opaque P { // expected-error{{'opaque' types are only implemented}} + return x + } +} + +func bar() -> __opaque P { + return 1 +} +func bas() -> __opaque P & Q { + return 1 +} +func zim() -> __opaque C { + return D() +} +func zang() -> __opaque C & P & Q { + return D() +} +func zung() -> __opaque AnyObject { + return D() +} +func zoop() -> __opaque Any { + return D() +} +func zup() -> __opaque Any & P { + return D() +} +func zip() -> __opaque AnyObject & P { + return D() +} +func zorp() -> __opaque Any & C & P { + return D() +} +func zlop() -> __opaque C & AnyObject & P { + return D() +} + +// Don't allow opaque types to propagate by inference into other global decls' +// types +struct Test { + let inferredOpaque = bar() // expected-error{{inferred type}} + let inferredOpaqueStructural = Optional(bar()) // expected-error{{inferred type}} + let inferredOpaqueStructural2 = (bar(), bas()) // expected-error{{inferred type}} +} + +//let zingle = {() -> __opaque P in 1 } // FIXME ex/pected-error{{'opaque' types are only implemented}} + +// Invalid positions + +typealias Foo = __opaque P // expected-error{{'opaque' types are only implemented}} + +func blibble(blobble: __opaque P) {} // expected-error{{'opaque' types are only implemented}} + +let blubble: () -> __opaque P = { 1 } // expected-error{{'opaque' types are only implemented}} + +func blib() -> P & __opaque Q { return 1 } // expected-error{{'opaque' should appear at the beginning}} +func blab() -> (P, __opaque Q) { return (1, 2) } // expected-error{{'opaque' types are only implemented}} +func blob() -> (__opaque P) -> P { return { $0 } } // expected-error{{'opaque' types are only implemented}} +func blorb(_: T) { } // expected-error{{'opaque' types are only implemented}} +func blub() -> T where T == __opaque P { return 1 } // expected-error{{'opaque' types are only implemented}} expected-error{{cannot convert}} + +protocol OP: __opaque P {} // expected-error{{'opaque' types are only implemented}} + +func foo() -> __opaque P { + let x = (__opaque P).self // expected-error*{{}} + return 1 +} + +// Invalid constraints + +let zug: __opaque Int = 1 // FIXME expected-error{{'opaque' types are only implemented}} +let zwang: __opaque () = () // FIXME expected-error{{'opaque' types are only implemented}} +let zwoggle: __opaque (() -> ()) = {} // FIXME expected-error{{'opaque' types are only implemented}} + +// Type-checking of expressions of opaque type + +func alice() -> __opaque P { return 1 } +func bob() -> __opaque P { return 1 } + +func grace(_ x: T) -> __opaque P { return x } + +func typeIdentity() { + do { + var a = alice() + a = alice() + a = bob() // expected-error{{}} + a = grace(1) // expected-error{{}} + a = grace("two") // expected-error{{}} + } + + do { + var af = alice + af = alice + af = bob // expected-error{{}} + af = grace // expected-error{{}} + } + + do { + var b = bob() + b = alice() // expected-error{{}} + b = bob() + b = grace(1) // expected-error{{}} + b = grace("two") // expected-error{{}} + } + + do { + var gi = grace(1) + gi = alice() // expected-error{{}} + gi = bob() // expected-error{{}} + gi = grace(2) + gi = grace("three") // expected-error{{}} + } + + do { + var gs = grace("one") + gs = alice() // expected-error{{}} + gs = bob() // expected-error{{}} + gs = grace(2) // expected-error{{}} + gs = grace("three") + } + + // The opaque type should conform to its constraining protocols + do { + let gs = grace("one") + var ggs = grace(gs) + ggs = grace(gs) + } + + // The opaque type should expose the members implied by its protocol + // constraints + // TODO: associated types + do { + var a = alice() + a.paul() + a.priscilla() + } +} + +func recursion(x: Int) -> __opaque P { + if x == 0 { + return 0 + } + return recursion(x: x - 1) +} + +func noReturnStmts() -> __opaque P { fatalError() } // expected-error{{no return statements}} + +func mismatchedReturnTypes(_ x: Bool, _ y: Int, _ z: String) -> __opaque P { // expected-error{{do not have matching underlying types}} + if x { + return y // expected-note{{underlying type 'Int'}} + } else { + return z // expected-note{{underlying type 'String'}} + } +} + +func jan() -> __opaque P { + return [marcia(), marcia(), marcia()] +} +func marcia() -> __opaque P { + return [marcia(), marcia(), marcia()] // expected-error{{defines the opaque type in terms of itself}} +} + +protocol R { + associatedtype S: P, Q // expected-note*{{}} + + func r_out() -> S + func r_in(_: S) +} + +extension Int: R { + func r_out() -> String { + return "" + } + func r_in(_: String) {} +} + +func candace() -> __opaque R { + return 0 +} +func doug() -> __opaque R { + return 0 +} + +func gary(_ x: T) -> __opaque R { + return x +} + +func sameType(_: T, _: T) {} + +func associatedTypeIdentity() { + let c = candace() + let d = doug() + + var cr = c.r_out() + cr = candace().r_out() + cr = doug().r_out() // expected-error{{}} + + var dr = d.r_out() + dr = candace().r_out() // expected-error{{}} + dr = doug().r_out() + + c.r_in(cr) + c.r_in(c.r_out()) + c.r_in(dr) // expected-error{{}} + c.r_in(d.r_out()) // expected-error{{}} + + d.r_in(cr) // expected-error{{}} + d.r_in(c.r_out()) // expected-error{{}} + d.r_in(dr) + d.r_in(d.r_out()) + + cr.paul() + cr.priscilla() + cr.quinn() + dr.paul() + dr.priscilla() + dr.quinn() + + sameType(cr, c.r_out()) + sameType(dr, d.r_out()) + sameType(cr, dr) // expected-error{{}} + sameType(gary(candace()).r_out(), gary(candace()).r_out()) + sameType(gary(doug()).r_out(), gary(doug()).r_out()) + sameType(gary(doug()).r_out(), gary(candace()).r_out()) // expected-error{{}} +} + +/* TODO: diagnostics +struct DoesNotConform {} + +func doesNotConform() -> __opaque P { + return DoesNotConform() +} +*/ + +