-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
Opaque types with resilience #22072
Conversation
} | ||
} | ||
|
||
auto interfaceSignature = GenericSignature::get(interfaceGenericParams, |
There was a problem hiding this comment.
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
} | ||
auto opaqueTy = OpaqueTypeArchetypeType::get(opaqueDecl, subs); | ||
auto metatype = MetatypeType::get(opaqueTy); | ||
opaqueDecl->setInterfaceType(metatype); |
There was a problem hiding this comment.
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.
@@ -1966,8 +1966,9 @@ auto AssociatedTypeInference::solve(ConformanceChecker &checker) | |||
if (replacement->hasDependentMember()) | |||
return None; | |||
|
|||
if (replacement->hasArchetype()) | |||
if (replacement->hasArchetype()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Useless edit here
There was a problem hiding this comment.
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.
getGenericSignature(interfaceSigID), | ||
getType(interfaceTypeID)->castTo<GenericTypeParamType>()); | ||
auto genericEnv = getGenericEnvironment(genericEnvID); | ||
opaqueDecl->setGenericEnvironment(genericEnv); |
There was a problem hiding this comment.
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
|
||
auto replacementParam = replacement->getAs<GenericTypeParamType>(); | ||
if (!replacementParam) | ||
llvm_unreachable("opaque types cannot currently be parameterized by non-identity type parameter mappings"); |
There was a problem hiding this comment.
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
auto opaqueInterfaceTy = Decl->getUnderlyingInterfaceType(); | ||
auto layout = signature->getLayoutConstraint(opaqueInterfaceTy); | ||
auto superclass = signature->getSuperclassBound(opaqueInterfaceTy); | ||
SmallVector<ProtocolDecl*, 4> protos; |
There was a problem hiding this comment.
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)
?
|
||
// Create a generic environment and bind the opaque archetype to the | ||
// opaque interface type from the decl's signature. | ||
auto env = signature->createGenericEnvironment(); |
There was a problem hiding this comment.
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?
lib/AST/ASTContext.cpp
Outdated
nullptr); | ||
auto env = signature->createGenericEnvironment(); | ||
env->addMapping(signature->getGenericParams()[0], result); | ||
result->Environment = env; |
There was a problem hiding this comment.
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?
ReplaceOpaqueTypesWithUnderlyingTypes::operator()(CanType maybeOpaqueType, | ||
Type replacementType, | ||
ProtocolDecl *protocol) const { | ||
auto abstractRef = ProtocolConformanceRef(protocol); |
There was a problem hiding this comment.
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
if (!anyChanged) | ||
return *this; | ||
|
||
// FIXME: This re-looks-up conformances instead of transforming them in |
There was a problem hiding this comment.
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?
return *this; | ||
} | ||
|
||
// Substitute the new root into the root of the interface type. |
There was a problem hiding this comment.
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.
lib/SILGen/SILGenBuilder.cpp
Outdated
@@ -156,6 +155,7 @@ InitExistentialValueInst *SILGenBuilder::createInitExistentialValue( | |||
|
|||
InitExistentialMetatypeInst *SILGenBuilder::createInitExistentialMetatype( | |||
SILLocation loc, SILValue metatype, SILType existentialType, | |||
CanType formalConcreteInstanceType, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
return RValue(SGF, E, opaque); | ||
} | ||
|
||
// If the opaque type is loadable, emit the subexpression and bitcast it. |
There was a problem hiding this comment.
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...
There was a problem hiding this comment.
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.
auto opaque1 = cast<OpaqueTypeArchetypeType>(desugar1); | ||
auto opaque2 = cast<OpaqueTypeArchetypeType>(desugar2); | ||
|
||
assert(!type2->is<LValueType>() && "Unexpected lvalue type!"); |
There was a problem hiding this comment.
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
a687a16
to
539efbf
Compare
18b8153
to
dece01a
Compare
4bc5f1e
to
d749086
Compare
} | ||
|
||
void addUnderlyingTypeAndConformances() { | ||
auto underlyingType = Type(O->getUnderlyingInterfaceType()) |
There was a problem hiding this comment.
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?
f002faf
to
88a05b7
Compare
…nesses. rdar://problem/49585457
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.)
…scripts. rdar://problem/49818962
…rdar://problem/49829836
c29dc4b
to
dbd3a48
Compare
@swift-ci Please test |
@swift-ci Please test source compatibility |
Build failed |
Build failed |
@swift-ci Please test Linux |
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.