SIL: More accurate for type lowering whether a type is trivial based on conditional Copyable requirements.

We want a conditionally-copyable type to still be classified as trivial in cases
where it's bitwise-copyable, has a trivial deinit, and is Copyable. The previous
implementation here only checked at the declaration level whether a type was
Copyable or not; get a more accurate answer by consulting the combination
of information in the substituted type and abstraction pattern we have
available during type lowering so that we classify definitely-copyable substitutions
of a conditionally-copyable type as trivial. Should fix rdar://123654553 and
rdar://123658878.
This commit is contained in:
Joe Groff
2024-02-27 15:01:20 -08:00
parent 0b580f7155
commit fe7049ed13
8 changed files with 215 additions and 15 deletions

View File

@@ -284,6 +284,83 @@ LayoutConstraint AbstractionPattern::getLayoutConstraint() const {
}
}
bool AbstractionPattern::isNoncopyable(CanType substTy) const {
auto copyable
= substTy->getASTContext().getProtocol(KnownProtocolKind::Copyable);
auto isDefinitelyCopyable = [&](CanType t) -> bool {
auto result = copyable->getParentModule()
->checkConformanceWithoutContext(substTy, copyable,
/*allowMissing=*/false);
return result.has_value() && !result.value().isInvalid();
};
// If the substituted type definitely conforms, that's authoritative.
if (isDefinitelyCopyable(substTy)) {
return false;
}
// If the substituted type is fully concrete, that's it. If there are unbound
// type variables in the type, then we may have to account for the upper
// abstraction bound from the abstraction pattern.
if (!substTy->hasTypeParameter()) {
return true;
}
switch (getKind()) {
case Kind::Opaque: {
// The abstraction pattern doesn't provide any more specific bounds.
return true;
}
case Kind::Type:
case Kind::Discard:
case Kind::ClangType: {
// See whether the abstraction pattern's context gives us an upper bound
// that ensures the type is copyable.
auto type = getType();
if (hasGenericSignature() && getType()->hasTypeParameter()) {
type = GenericEnvironment::mapTypeIntoContext(
getGenericSignature().getGenericEnvironment(), getType())
->getReducedType(getGenericSignature());
}
return !isDefinitelyCopyable(type);
}
case Kind::Tuple: {
// A tuple is noncopyable if any element is.
if (doesTupleVanish()) {
return getVanishingTupleElementPatternType().value()
.isNoncopyable(substTy);
}
auto substTupleTy = cast<TupleType>(substTy);
for (unsigned i = 0, e = getNumTupleElements(); i < e; ++i) {
if (getTupleElementType(i).isNoncopyable(substTupleTy.getElementType(i))){
return true;
}
}
return false;
}
// Functions are, at least for now, always copyable.
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::ObjCMethodType:
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return false;
case Kind::Invalid:
llvm_unreachable("asking invalid abstraction pattern");
}
}
bool AbstractionPattern::matchesTuple(CanType substType) const {
switch (getKind()) {
case Kind::Invalid: