Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opaque types with resilience #22072

Merged
merged 46 commits into from Apr 18, 2019
Merged

Opaque types with resilience #22072

merged 46 commits into from Apr 18, 2019

Conversation

@jckarter
Copy link
Member

@jckarter jckarter commented Jan 23, 2019

A continuation of #21137. This branch adds "proper" resilience support. Opaque types can now enter the SIL type system, and will be able to be represented at runtime with opaque accessors for their associated metadata.

}
}

auto interfaceSignature = GenericSignature::get(interfaceGenericParams,
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be cleaner if you use a GSB instead; then you can add a requirement with a class or any kind of existential in it and it will flatten it into the right thing. In particular, there's no guarantee that the order in which you're adding stuff above is the right order to get a canonical generic signature

Loading

}
auto opaqueTy = OpaqueTypeArchetypeType::get(opaqueDecl, subs);
auto metatype = MetatypeType::get(opaqueTy);
opaqueDecl->setInterfaceType(metatype);
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code for setting the type here is the same as in deserialization. Take a look at how NominalTypeDecl and AssociatedTypeDecl have computeType() methods; OpaqueTypeDecl should also have one.

Loading

@@ -1966,8 +1966,9 @@ auto AssociatedTypeInference::solve(ConformanceChecker &checker)
if (replacement->hasDependentMember())
return None;

if (replacement->hasArchetype())
if (replacement->hasArchetype()) {
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless edit here

Loading

Copy link
Member Author

@jckarter jckarter Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought LLVM style was always to brace if blocks. It's more maintainable regardless.

Loading

getGenericSignature(interfaceSigID),
getType(interfaceTypeID)->castTo<GenericTypeParamType>());
auto genericEnv = getGenericEnvironment(genericEnvID);
opaqueDecl->setGenericEnvironment(genericEnv);
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For later: there's a mechanism to lazily deserialize generic environments. We do this already for generic functions and types; you might want to look into doing it here

Loading


auto replacementParam = replacement->getAs<GenericTypeParamType>();
if (!replacementParam)
llvm_unreachable("opaque types cannot currently be parameterized by non-identity type parameter mappings");
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: lines longer than 80 characters

Loading

auto opaqueInterfaceTy = Decl->getUnderlyingInterfaceType();
auto layout = signature->getLayoutConstraint(opaqueInterfaceTy);
auto superclass = signature->getSuperclassBound(opaqueInterfaceTy);
SmallVector<ProtocolDecl*, 4> protos;
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you just do protos = signature->getConformsTo(opaqueInterfaceTy)?

Loading


// Create a generic environment and bind the opaque archetype to the
// opaque interface type from the decl's signature.
auto env = signature->createGenericEnvironment();
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly for later: can you lazily create the generic environment?

Loading

nullptr);
auto env = signature->createGenericEnvironment();
env->addMapping(signature->getGenericParams()[0], result);
result->Environment = env;
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually a regression. Can you lazily create the generic environment?

Loading

lib/AST/Decl.cpp Outdated Show resolved Hide resolved
Loading
lib/AST/Decl.cpp Show resolved Hide resolved
Loading
ReplaceOpaqueTypesWithUnderlyingTypes::operator()(CanType maybeOpaqueType,
Type replacementType,
ProtocolDecl *protocol) const {
auto abstractRef = ProtocolConformanceRef(protocol);
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is almost identical to the above

Loading

if (!anyChanged)
return *this;

// FIXME: This re-looks-up conformances instead of transforming them in
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps subst() should handle opaque types directly and transform() should not attempt the substitution here?

Loading

return *this;
}

// Substitute the new root into the root of the interface type.
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like this should only need to happen in subst() too.

Loading

@@ -156,6 +155,7 @@ InitExistentialValueInst *SILGenBuilder::createInitExistentialValue(

InitExistentialMetatypeInst *SILGenBuilder::createInitExistentialMetatype(
SILLocation loc, SILValue metatype, SILType existentialType,
CanType formalConcreteInstanceType,
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need this? The instance type of a metatype is unlowered, so it should match the formal instance type.

Loading

Copy link
Member Author

@jckarter jckarter Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was necessary to support the hack of substituting out opaque types everywhere in SILGen, but I can back it out now.

Loading

return RValue(SGF, E, opaque);
}

// If the opaque type is loadable, emit the subexpression and bitcast it.
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if opaque types should be more like existentials, with special instructions to project an address or wrap a loadable value...

Loading

Copy link
Member Author

@jckarter jckarter Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add special instructions, but I don't know that it's worth it. The SIL passes already know how to deal with specializing bitcasts, and if we added specific instructions for underlying-to-opaque and the opposite conversion, they'd have to all be taught about those new instructions which are 99% semantically the same.

Loading

auto opaque1 = cast<OpaqueTypeArchetypeType>(desugar1);
auto opaque2 = cast<OpaqueTypeArchetypeType>(desugar2);

assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
Copy link
Member

@slavapestov slavapestov Jan 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type1 and type2 will never be LValueType at this point, so you can remove the cargo cult

Loading

lib/Sema/CSSimplify.cpp Show resolved Hide resolved
Loading
lib/Sema/CSSimplify.cpp Show resolved Hide resolved
Loading
@jckarter jckarter force-pushed the opaque-type-runtime branch 3 times, most recently from a687a16 to 539efbf Feb 4, 2019
@jckarter jckarter force-pushed the opaque-type-runtime branch 2 times, most recently from 18b8153 to dece01a Feb 12, 2019
@jckarter jckarter force-pushed the opaque-type-runtime branch 5 times, most recently from 4bc5f1e to d749086 Feb 26, 2019
}

void addUnderlyingTypeAndConformances() {
auto underlyingType = Type(O->getUnderlyingInterfaceType())
Copy link
Member

@slavapestov slavapestov Mar 13, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a utility method on OpaqueTypeDecl?

Loading

@jckarter jckarter force-pushed the opaque-type-runtime branch from f002faf to 88a05b7 Mar 15, 2019
jckarter added 21 commits Apr 17, 2019
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.)
@jckarter jckarter force-pushed the opaque-type-runtime branch from c29dc4b to dbd3a48 Apr 17, 2019
@jckarter
Copy link
Member Author

@jckarter jckarter commented Apr 18, 2019

@swift-ci Please test

Loading

@jckarter
Copy link
Member Author

@jckarter jckarter commented Apr 18, 2019

@swift-ci Please test source compatibility

Loading

@swift-ci
Copy link
Contributor

@swift-ci swift-ci commented Apr 18, 2019

Build failed
Swift Test OS X Platform
Git Sha - 577f14fe900015a7b2878080af7bfd98bbc5344a

Loading

@swift-ci
Copy link
Contributor

@swift-ci swift-ci commented Apr 18, 2019

Build failed
Swift Test Linux Platform
Git Sha - 577f14fe900015a7b2878080af7bfd98bbc5344a

Loading

@jckarter
Copy link
Member Author

@jckarter jckarter commented Apr 18, 2019

@swift-ci Please test Linux

Loading

@jckarter jckarter merged commit a8c2b50 into apple:master Apr 18, 2019
6 checks passed
Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants