Skip to content

Commit

Permalink
Parsable interface and type reconstruction support for opaque types.
Browse files Browse the repository at this point in the history
When printing a swiftinterface, represent opaque result types using an attribute that refers to
the mangled name of the defining decl for the opaque type. To turn this back into a reference
to the right decl's implicit OpaqueTypeDecl, use type reconstruction. Since type reconstruction
doesn't normally concern itself with non-type decls, set up a lookup table in SourceFiles and
ModuleFiles to let us handle the mapping from mangled name to opaque type decl in type
reconstruction.

(Since we're invoking type reconstruction during type checking, when the module hasn't yet been
fully validated, we need to plumb a LazyResolver into the ASTBuilder in an unsightly way. Maybe
there's a better way to do this... Longer term, at least, this surface design gives space for
doing things more the right way--a more request-ified decl validator ought to be able to naturally
lazily service this request without the LazyResolver reference, and if type reconstruction in
the future learns how to reconstruct non-type decls, then the lookup tables can go away.)
  • Loading branch information
jckarter committed Apr 17, 2019
1 parent 733b08b commit 399332b
Show file tree
Hide file tree
Showing 29 changed files with 613 additions and 47 deletions.
3 changes: 3 additions & 0 deletions include/swift/AST/ASTDemangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class ASTBuilder {
using BuiltTypeDecl = swift::GenericTypeDecl *; // nominal or type alias
using BuiltProtocolDecl = swift::ProtocolDecl *;
explicit ASTBuilder(ASTContext &ctx) : Ctx(ctx) {}

/// The resolver to use for type checking, if necessary.
LazyResolver *Resolver = nullptr;

ASTContext &getASTContext() { return Ctx; }
DeclContext *getNotionalDC();
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ TYPE_ATTR(yield_many)
TYPE_ATTR(thin)
TYPE_ATTR(thick)

// Generated interface attributes
TYPE_ATTR(_opaqueReturnTypeOf)

// Schema for DECL_ATTR:
//
// - Attribute name.
Expand Down
12 changes: 12 additions & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ class TypeAttributes {

// For an opened existential type, the known ID.
Optional<UUID> OpenedID;

// For a reference to an opaque return type, the mangled name and argument
// index into the generic signature.
struct OpaqueReturnTypeRef {
StringRef mangledName;
unsigned index;
};
Optional<OpaqueReturnTypeRef> OpaqueReturnTypeOf;

TypeAttributes() {}

Expand All @@ -84,6 +92,10 @@ class TypeAttributes {
return AttrLocs[A];
}

void setOpaqueReturnTypeOf(StringRef mangling, unsigned index) {
OpaqueReturnTypeOf = OpaqueReturnTypeRef{mangling, index};
}

void setAttr(TypeAttrKind A, SourceLoc L) {
assert(!L.isInvalid() && "Cannot clear attribute with this method");
AttrLocs[A] = L;
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -3727,6 +3727,9 @@ WARNING(witness_swift3_objc_inference,none,
"'@objc' inference deprecated in Swift 4",
(DescriptiveDeclKind, DeclName, Type))

ERROR(no_opaque_return_type_of,none,
"unable to resolve type for _opaqueReturnTypeOf attribute", ())


ERROR(objc_observing_accessor, none,
"observing accessors are not allowed to be marked @objc", ())
Expand Down
35 changes: 34 additions & 1 deletion include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ namespace swift {
class FileUnit;
class FuncDecl;
class InfixOperatorDecl;
class LazyResolver;
class LinkLibrary;
class LookupCache;
class ModuleLoader;
Expand Down Expand Up @@ -341,6 +342,11 @@ class ModuleDecl : public DeclContext, public TypeDecl {
/// This does a simple local lookup, not recursively looking through imports.
TypeDecl *lookupLocalType(StringRef MangledName) const;

/// Look up an opaque return type by the mangled name of the declaration
/// that defines it.
OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName,
LazyResolver *resolver);

/// Find ValueDecls in the module and pass them to the given consumer object.
///
/// This does a simple local lookup, not recursively looking through imports.
Expand Down Expand Up @@ -642,6 +648,13 @@ class FileUnit : public DeclContext {
virtual TypeDecl *lookupLocalType(StringRef MangledName) const {
return nullptr;
}

/// Look up an opaque return type by the mangled name of the declaration
/// that defines it.
virtual OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName,
LazyResolver *resolver) {
return nullptr;
}

/// Directly look for a nested type declared within this module inside the
/// given nominal type (including any extensions).
Expand Down Expand Up @@ -740,6 +753,9 @@ class FileUnit : public DeclContext {
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
virtual void getLocalTypeDecls(SmallVectorImpl<TypeDecl*> &results) const {}

virtual void
getOpaqueReturnTypeDecls(SmallVectorImpl<OpaqueTypeDecl*> &results) const {}

/// Adds all top-level decls to the given vector.
///
Expand Down Expand Up @@ -982,6 +998,12 @@ class SourceFile final : public FileUnit {

/// The list of local type declarations in the source file.
llvm::SetVector<TypeDecl *> LocalTypeDecls;

/// The set of validated opaque return type decls in the source file.
llvm::StringMap<OpaqueTypeDecl *> ValidatedOpaqueReturnTypes;
/// The set of parsed decls with opaque return types that have not yet
/// been validated.
llvm::DenseSet<ValueDecl *> UnvalidatedDeclsWithOpaqueReturnTypes;

/// A set of special declaration attributes which require the
/// Foundation module to be imported to work. If the foundation
Expand Down Expand Up @@ -1089,6 +1111,8 @@ class SourceFile final : public FileUnit {

virtual void
getLocalTypeDecls(SmallVectorImpl<TypeDecl*> &results) const override;
virtual void
getOpaqueReturnTypeDecls(SmallVectorImpl<OpaqueTypeDecl*> &results) const override;

virtual void
getImportedModules(SmallVectorImpl<ModuleDecl::ImportedModule> &imports,
Expand Down Expand Up @@ -1262,6 +1286,15 @@ class SourceFile final : public FileUnit {
void setSyntaxRoot(syntax::SourceFileSyntax &&Root);
bool hasSyntaxRoot() const;

OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName,
LazyResolver *resolver) override;

void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) {
UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd);
}

void markDeclWithOpaqueResultTypeAsValidated(ValueDecl *vd);

private:

/// If not None, the underlying vector should contain tokens of this source file.
Expand Down Expand Up @@ -1300,7 +1333,7 @@ class BuiltinUnit final : public FileUnit {
getDiscriminatorForPrivateValue(const ValueDecl *D) const override {
llvm_unreachable("no private values in the Builtin module");
}

static bool classof(const FileUnit *file) {
return file->getKind() == FileUnitKind::Builtin;
}
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,10 @@ struct PrintOptions {
/// Whether to skip keywords with a prefix of underscore such as __consuming.
bool SkipUnderscoredKeywords = false;

/// Whether to print declarations with opaque return types with a stable,
/// parsable internal syntax.
bool PrintStableReferencesToOpaqueReturnTypes = false;

/// Whether to print decl attributes that are only used internally,
/// such as _silgen_name, transparent, etc.
bool PrintUserInaccessibleAttrs = true;
Expand Down
4 changes: 2 additions & 2 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -4770,7 +4770,7 @@ class OpaqueTypeArchetypeType final : public ArchetypeType,
static OpaqueTypeArchetypeType *get(OpaqueTypeDecl *Decl,
SubstitutionMap Substitutions);

OpaqueTypeDecl *getOpaqueDecl() const {
OpaqueTypeDecl *getDecl() const {
return OpaqueDecl;
}
SubstitutionMap getSubstitutions() const {
Expand All @@ -4797,7 +4797,7 @@ class OpaqueTypeArchetypeType final : public ArchetypeType,
SubstitutionMap Substitutions);

void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getOpaqueDecl(), getSubstitutions());
Profile(ID, getDecl(), getSubstitutions());
};

private:
Expand Down
12 changes: 12 additions & 0 deletions include/swift/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,10 @@ class ModuleFile
class LocalDeclTableInfo;
using SerializedLocalDeclTable =
llvm::OnDiskIterableChainedHashTable<LocalDeclTableInfo>;

using OpaqueReturnTypeDeclTableInfo = LocalDeclTableInfo;
using SerializedOpaqueReturnTypeDeclTable =
llvm::OnDiskIterableChainedHashTable<OpaqueReturnTypeDeclTableInfo>;

class NestedTypeDeclsTableInfo;
using SerializedNestedTypeDeclsTable =
Expand All @@ -408,6 +412,7 @@ class ModuleFile
std::unique_ptr<SerializedDeclTable> OperatorMethodDecls;
std::unique_ptr<SerializedExtensionTable> ExtensionDecls;
std::unique_ptr<SerializedLocalDeclTable> LocalTypeDecls;
std::unique_ptr<SerializedOpaqueReturnTypeDeclTable> OpaqueReturnTypeDecls;
std::unique_ptr<SerializedNestedTypeDeclsTable> NestedTypeDecls;
std::unique_ptr<SerializedDeclMemberNamesTable> DeclMemberNames;

Expand Down Expand Up @@ -705,6 +710,10 @@ class ModuleFile

/// Searches the module's local type decls for the given mangled name.
TypeDecl *lookupLocalType(StringRef MangledName);

/// Search the module's opaque return type decls for the one corresponding to
/// the given mangled name.
OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName);

/// Searches the module's nested type decls table for the given member of
/// the given type.
Expand Down Expand Up @@ -785,6 +794,9 @@ class ModuleFile

/// Adds all local type decls to the given vector.
void getLocalTypeDecls(SmallVectorImpl<TypeDecl*> &Results);

/// Add all opaque return type decls in the module to the given vector.
void getOpaqueReturnTypeDecls(SmallVectorImpl<OpaqueTypeDecl*> &Results);

/// Adds all top-level decls to the given vector.
///
Expand Down
1 change: 1 addition & 0 deletions include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -1704,6 +1704,7 @@ namespace index_block {
LOCAL_DECL_CONTEXT_OFFSETS,
DECL_CONTEXT_OFFSETS,
LOCAL_TYPE_DECLS,
OPAQUE_RETURN_TYPE_DECLS,
GENERIC_ENVIRONMENT_OFFSETS,
NORMAL_CONFORMANCE_OFFSETS,
SIL_LAYOUT_OFFSETS,
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Serialization/SerializedModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ class SerializedASTFile final : public LoadedFile {
SmallVectorImpl<ValueDecl*> &results) const override;

virtual TypeDecl *lookupLocalType(StringRef MangledName) const override;

virtual OpaqueTypeDecl *
lookupOpaqueResultType(StringRef MangledName, LazyResolver *resolver) override;

virtual TypeDecl *
lookupNestedType(Identifier name,
Expand Down Expand Up @@ -269,6 +272,8 @@ class SerializedASTFile final : public LoadedFile {

virtual void
getLocalTypeDecls(SmallVectorImpl<TypeDecl*> &results) const override;
virtual void
getOpaqueReturnTypeDecls(SmallVectorImpl<OpaqueTypeDecl*> &results) const override;

virtual void getDisplayDecls(SmallVectorImpl<Decl*> &results) const override;

Expand Down
29 changes: 28 additions & 1 deletion lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ static SubstitutionMap
createSubstitutionMapFromGenericArgs(GenericSignature *genericSig,
ArrayRef<Type> args,
ModuleDecl *moduleDecl) {
if (!genericSig)
return SubstitutionMap();

SmallVector<GenericTypeParamType *, 4> genericParams;
genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
if (canonical)
Expand Down Expand Up @@ -250,7 +253,31 @@ Type ASTBuilder::createBoundGenericType(GenericTypeDecl *decl,
Type ASTBuilder::resolveOpaqueType(NodePointer opaqueDescriptor,
ArrayRef<Type> args,
unsigned ordinal) {
// TODO
if (opaqueDescriptor->getKind() == Node::Kind::OpaqueReturnTypeOf) {
auto definingDecl = opaqueDescriptor->getChild(0);
auto mangledName = mangleNode(definingDecl);
auto moduleNode = findModuleNode(definingDecl);
if (!moduleNode)
return Type();
auto parentModule = findModule(findModuleNode(definingDecl));
if (!parentModule)
return Type();

auto opaqueDecl = parentModule->lookupOpaqueResultType(mangledName,
Resolver);
if (!opaqueDecl)
return Type();
// TODO: multiple opaque types
assert(ordinal == 0 && "not implemented");
if (ordinal != 0)
return Type();

SubstitutionMap subs = createSubstitutionMapFromGenericArgs(
opaqueDecl->getGenericSignature(), args, parentModule);
return OpaqueTypeArchetypeType::get(opaqueDecl, subs);
}

// TODO: named opaque types
return Type();
}

Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3474,7 +3474,7 @@ namespace {
void visitOpaqueTypeArchetypeType(OpaqueTypeArchetypeType *T,
StringRef label) {
printArchetypeCommon(T, "opaque_type", label);
printField("decl", T->getOpaqueDecl()->getNamingDecl()->printRef());
printField("decl", T->getDecl()->getNamingDecl()->printRef());
if (!T->getSubstitutions().empty()) {
OS << '\n';
SmallPtrSet<const ProtocolConformance *, 4> Dumped;
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) {
// If this is the opaque return type of the declaration currently being
// mangled, use a short mangling to represent it.
auto opaqueType = cast<OpaqueTypeArchetypeType>(tybase);
auto opaqueDecl = opaqueType->getOpaqueDecl();
auto opaqueDecl = opaqueType->getDecl();
if (opaqueDecl->getNamingDecl() == forDecl) {
if (opaqueType->getSubstitutions().isIdentity()) {
return appendOperator("Qr");
Expand Down

0 comments on commit 399332b

Please sign in to comment.