From dd2b51d6dcfc13c05665dd4a989e9745f0b5a7a4 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Fri, 14 Dec 2018 18:32:09 -0800 Subject: [PATCH] Add an OpaqueTypeArchetypeType subclass. --- include/swift/AST/GenericSignature.h | 4 + include/swift/AST/TypeNodes.def | 1 + include/swift/AST/Types.h | 64 ++++++++++++++ lib/AST/ASTContext.cpp | 127 +++++++++++++++++++++++++++ lib/AST/ASTDumper.cpp | 14 +++ lib/AST/ASTMangler.cpp | 4 + lib/AST/ASTPrinter.cpp | 14 +++ lib/AST/GenericSignature.cpp | 8 ++ lib/AST/Type.cpp | 82 ++++++++++++++++- lib/AST/TypeWalker.cpp | 8 ++ lib/IRGen/Fulfillment.cpp | 1 + lib/IRGen/GenType.cpp | 3 + lib/IRGen/IRGenDebugInfo.cpp | 3 + lib/Sema/CSSimplify.cpp | 59 ++++++++++--- lib/Sema/TypeCheckGeneric.cpp | 24 +++-- lib/Serialization/Serialization.cpp | 3 + test/type/opaque.swift | 91 ++++++++++++++++--- 17 files changed, 474 insertions(+), 36 deletions(-) diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index d51a9c7960a..4ab856af978 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -307,6 +307,10 @@ public: /// /// 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/TypeNodes.def b/include/swift/AST/TypeNodes.def index fd054839041..1e15e580f2f 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/Types.h b/include/swift/AST/Types.h index 96f903e367c..5e25a89727c 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; @@ -4728,6 +4730,65 @@ private: 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; + + /// The generic signature used to build out this archetype, and its + /// nested archetypes. + GenericSignature *BoundSignature; + +public: + /// 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 underlying type of the opaque type, if it's known. + Type getUnderlyingType() const; + + 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, + GenericSignature *BoundSignature, + Type InterfaceType, + ArrayRef ConformsTo, + Type Superclass, LayoutConstraint Layout); +}; +BEGIN_CAN_TYPE_WRAPPER(OpaqueTypeArchetypeType, ArchetypeType) +END_CAN_TYPE_WRAPPER(OpaqueTypeArchetypeType, ArchetypeType) + /// An archetype that represents the dynamic type of an opened existential. class OpenedArchetypeType final : public ArchetypeType, private ArchetypeTrailingObjects @@ -4834,6 +4895,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(); } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 66c58d907fd..62a3be78f74 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -323,6 +323,7 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL) llvm::FoldingSet BoundGenericTypes; llvm::FoldingSet ProtocolCompositionTypes; llvm::FoldingSet LayoutConstraints; + llvm::FoldingSet OpaqueArchetypes; /// The set of function types. llvm::FoldingSet FunctionTypes; @@ -4177,6 +4178,132 @@ 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. + RecursiveTypeProperties properties = {}; + 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, + signature, + opaqueInterfaceTy, + protos, superclass, layout); + + // 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(); diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 1c1ef7131cb..d6c4fcff89b 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3460,6 +3460,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 83c673c4c14..bfee21553ba 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -955,6 +955,10 @@ void ASTMangler::appendType(Type type) { case TypeKind::NestedArchetype: llvm_unreachable("Cannot mangle free-standing archetypes"); + case TypeKind::OpaqueTypeArchetype: +#warning "todo" + llvm_unreachable("TODO"); + case TypeKind::DynamicSelf: { auto dynamicSelf = cast(tybase); if (dynamicSelf->getSelfType()->getAnyNominal()) { diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index ddbc4b2a702..9fbe298983e 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4140,6 +4140,20 @@ public: void visitPrimaryArchetypeType(PrimaryArchetypeType *T) { printArchetypeCommon(T); } + + void visitOpaqueTypeArchetypeType(OpaqueTypeArchetypeType *T) { +#warning "todo" + 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/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 255c350de9c..76b6732317f 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/Type.cpp b/lib/AST/Type.cpp index 6a72f6d6006..e242512ba35 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(); @@ -2413,6 +2414,22 @@ NestedArchetypeType::NestedArchetypeType(const ASTContext &Ctx, { } +OpaqueTypeArchetypeType::OpaqueTypeArchetypeType(OpaqueTypeDecl *OpaqueDecl, + SubstitutionMap Substitutions, + RecursiveTypeProperties Props, + GenericSignature *BoundSignature, + Type InterfaceType, + ArrayRef ConformsTo, + Type Superclass, LayoutConstraint Layout) + : ArchetypeType(TypeKind::OpaqueTypeArchetype, OpaqueDecl->getASTContext(), + Props, + InterfaceType, ConformsTo, Superclass, Layout), + OpaqueDecl(OpaqueDecl), + Substitutions(Substitutions), + BoundSignature(BoundSignature) +{ +} + CanNestedArchetypeType NestedArchetypeType::getNew( const ASTContext &Ctx, ArchetypeType *Parent, @@ -2431,7 +2448,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)); } @@ -2454,7 +2471,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)); } @@ -2616,6 +2633,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) { @@ -3005,6 +3030,17 @@ static Type substType(Type derivedType, // error. if (isa(substOrig)) return Type(type); + // Opaque types also can't be directly substituted, but we can substitute + // the generic arguments. + if (auto opaque = dyn_cast(substOrig)) { + if (!opaque->hasArchetype() + && !opaque->hasTypeParameter()) + return Type(type); + + auto newSubs = opaque->getSubstitutions().subst(substitutions, lookupConformances); + auto newTy = OpaqueTypeArchetypeType::get(opaque->getOpaqueDecl(), newSubs); + return Type(newTy); + } // For nested archetypes, we can substitute the parent. auto nestedArchetype = cast(substOrig); @@ -3388,15 +3424,19 @@ 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::NestedArchetype: case TypeKind::Error: case TypeKind::Unresolved: case TypeKind::TypeVariable: case TypeKind::GenericTypeParam: case TypeKind::SILToken: + case TypeKind::Module: return *this; case TypeKind::Enum: @@ -3551,6 +3591,39 @@ 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::ExistentialMetatype: { auto meta = cast(base); @@ -3998,7 +4071,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/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index 8c6ad7802e1..e148704ade7 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -169,6 +169,14 @@ class Traversal : public TypeVisitor return false; } + + bool visitOpaqueTypeArchetypeType(OpaqueTypeArchetypeType *ty) { + for (auto arg : ty->getSubstitutions().getReplacementTypes()) { + if (doIt(arg)) + return true; + } + return false; + } bool visitTypeVariableType(TypeVariableType *ty) { return false; } diff --git a/lib/IRGen/Fulfillment.cpp b/lib/IRGen/Fulfillment.cpp index 285e0a6cafc..52fcc5b4f50 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/GenType.cpp b/lib/IRGen/GenType.cpp index 913b052ac55..97a957e97ef 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -1778,6 +1778,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 2251fa7510c..e3908e09084 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1367,6 +1367,9 @@ private: 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/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index f4f5f918644..d90d1a48afa 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1565,11 +1565,42 @@ 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 opaque1 = type1->getAs()) { + auto opaque2 = type2->castTo(); + + 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(); @@ -1604,19 +1635,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 @@ -2382,6 +2401,19 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality); break; } + + 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; + } + } } @@ -2941,6 +2973,7 @@ ConstraintSystem::simplifyConstructionConstraint( case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: + case TypeKind::OpaqueTypeArchetype: case TypeKind::DynamicSelf: case TypeKind::ProtocolComposition: case TypeKind::Protocol: diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index bd58b3b0f56..789e0153739 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -177,6 +177,11 @@ 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::FunctionResult); @@ -203,8 +208,8 @@ static Type getOpaqueResultType(TypeChecker &tc, SmallVector interfaceRequirements; auto originatingDC = originatingDecl->getInnermostDeclContext(); - if (auto outerGenericSignature = - originatingDC->getGenericSignatureOfContext()) { + auto outerGenericSignature = originatingDC->getGenericSignatureOfContext(); + if (outerGenericSignature) { std::copy(outerGenericSignature->getGenericParams().begin(), outerGenericSignature->getGenericParams().end(), std::back_inserter(interfaceGenericParams)); @@ -262,12 +267,15 @@ static Type getOpaqueResultType(TypeChecker &tc, originatingDecl->setOpaqueResultTypeDecl(opaqueDecl); - // TODO: The declared interface type should be an opaque ArchetypeType, - // when that's supported. - auto errorType = ErrorType::get(constraintTypeLoc.getType()); - auto errorMetatype = MetatypeType::get(errorType); - opaqueDecl->setInterfaceType(errorMetatype); - return errorType; + // 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. diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 922dab2a6f1..5cd67101909 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3863,6 +3863,9 @@ void Serializer::writeType(Type ty) { break; } + case TypeKind::OpaqueTypeArchetype: + llvm_unreachable("todo"); + case TypeKind::PrimaryArchetype: { auto archetypeTy = cast(ty.getPointer()); auto env = archetypeTy->getGenericEnvironment(); diff --git a/test/type/opaque.swift b/test/type/opaque.swift index 765893d66b8..968f73283f5 100644 --- a/test/type/opaque.swift +++ b/test/type/opaque.swift @@ -4,12 +4,16 @@ // function decls, but the opaque types are not themselves formed, resolved, // or checked yet. -protocol P {} -protocol Q {} -extension Int: P, Q {} +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() {} } class C {} -class D: C, P, Q {} +class D: C, P, Q { func paul() {}; func priscilla() {}; func quinn() {} } // TODO: Should be valid @@ -19,22 +23,22 @@ var computedFoo: __opaque P { // FIXME expected-error{{'opaque' types are only set { _ = newValue + 1 } } func bar() -> __opaque P { - return 1 + return 1 // FIXME expected-error{{convert}} } func bas() -> __opaque P & Q { - return 1 + return 1 // FIXME expected-error{{convert}} } func zim() -> __opaque C { - return D() + return D() // FIXME expected-error{{convert}} } func zang() -> __opaque C & P & Q { - return D() + return D() // FIXME expected-error{{convert}} } func zung() -> __opaque AnyObject { - return D() + return D() // FIXME expected-error{{convert}} } func zoop() -> __opaque Any { - return D() + return D() // FIXME expected-error{{convert}} } //let zingle = {() -> __opaque P in 1 } // FIXME ex/pected-error{{'opaque' types are only implemented}} @@ -47,7 +51,7 @@ func blibble(blobble: __opaque P) {} // expected-error{{'opaque' types are only let blubble: () -> __opaque P = { 1 } // expected-error{{'opaque' types are only implemented}} -func blib() -> P & __opaque Q { return 1 } // FIXME expected-error{{'opaque' should appear at the beginning}} +func blib() -> P & __opaque Q { return 1 } // expected-error{{'opaque' should appear at the beginning}} // FIXME expected-error{{convert}} 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}} @@ -56,3 +60,68 @@ func blob() -> (__opaque P) -> P { return { $0 } } // expected-error{{'opaque' t 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 } // FIXME expected-error{{convert}} +func bob() -> __opaque P { return 1 } // FIXME expected-error{{convert}} + +func grace(_ x: T) -> __opaque P { return x } // FIXME expected-error{{convert}} + +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() + } +} +