|
12 | 12 |
|
13 | 13 | #define DEBUG_TYPE "sil-devirtualize-utility"
|
14 | 14 | #include "swift/SILOptimizer/Utils/Devirtualize.h"
|
| 15 | +#include "swift/AST/ConformanceLookup.h" |
15 | 16 | #include "swift/AST/Decl.h"
|
16 | 17 | #include "swift/AST/GenericSignature.h"
|
17 | 18 | #include "swift/AST/ProtocolConformance.h"
|
@@ -386,6 +387,93 @@ swift::getExactDynamicTypeOfUnderlyingObject(SILValue instance,
|
386 | 387 | return getExactDynamicType(instance, cha, /* forUnderlyingObject */ true);
|
387 | 388 | }
|
388 | 389 |
|
| 390 | +/// Combine two substitution maps as follows. |
| 391 | +/// |
| 392 | +/// The result is written in terms of the generic parameters of 'genericSig'. |
| 393 | +/// |
| 394 | +/// Generic parameters with a depth less than 'firstDepth' |
| 395 | +/// come from 'firstSubMap'. |
| 396 | +/// |
| 397 | +/// Generic parameters with a depth greater than 'firstDepth' come from |
| 398 | +/// 'secondSubMap', but are looked up starting with a depth or index of |
| 399 | +/// 'secondDepth'. |
| 400 | +/// |
| 401 | +/// The 'how' parameter determines if we're looking at the depth or index. |
| 402 | +static SubstitutionMap |
| 403 | +combineSubstitutionMaps(SubstitutionMap firstSubMap, |
| 404 | + SubstitutionMap secondSubMap, |
| 405 | + unsigned firstDepth, |
| 406 | + unsigned secondDepth, |
| 407 | + GenericSignature genericSig) { |
| 408 | + auto &ctx = genericSig->getASTContext(); |
| 409 | + |
| 410 | + auto replaceGenericParameter = [&](Type type) -> std::optional<Type> { |
| 411 | + if (auto gp = type->getAs<GenericTypeParamType>()) { |
| 412 | + if (gp->getDepth() < firstDepth) |
| 413 | + return Type(); |
| 414 | + return Type(GenericTypeParamType::get(gp->isParameterPack(), |
| 415 | + gp->getDepth() + secondDepth - |
| 416 | + firstDepth, |
| 417 | + gp->getIndex(), ctx)); |
| 418 | + } |
| 419 | + |
| 420 | + return std::nullopt; |
| 421 | + }; |
| 422 | + |
| 423 | + return SubstitutionMap::get( |
| 424 | + genericSig, |
| 425 | + [&](SubstitutableType *type) { |
| 426 | + if (auto replacement = replaceGenericParameter(type)) |
| 427 | + if (*replacement) |
| 428 | + return replacement->subst(secondSubMap); |
| 429 | + return Type(type).subst(firstSubMap); |
| 430 | + }, |
| 431 | + [&](CanType type, Type substType, ProtocolDecl *proto) { |
| 432 | + if (auto replacement = type.transformRec(replaceGenericParameter)) |
| 433 | + return secondSubMap.lookupConformance(replacement->getCanonicalType(), |
| 434 | + proto); |
| 435 | + if (auto conformance = firstSubMap.lookupConformance(type, proto)) |
| 436 | + return conformance; |
| 437 | + |
| 438 | + // We might not have enough information in the substitution maps alone. |
| 439 | + // |
| 440 | + // Eg, |
| 441 | + // |
| 442 | + // class Base<T1> { |
| 443 | + // func foo<U1>(_: U1) where T1 : P {} |
| 444 | + // } |
| 445 | + // |
| 446 | + // class Derived<T2> : Base<Foo<T2>> { |
| 447 | + // override func foo<U2>(_: U2) where T2 : Q {} |
| 448 | + // } |
| 449 | + // |
| 450 | + // Suppose we're devirtualizing a call to Base.foo() on a value whose |
| 451 | + // type is known to be Derived<Bar>. We start with substitutions written |
| 452 | + // in terms of Base.foo()'s generic signature: |
| 453 | + // |
| 454 | + // <T1, U1 where T1 : P> |
| 455 | + // T1 := Foo<Bar> |
| 456 | + // T1 : P := Foo<Bar> : P |
| 457 | + // |
| 458 | + // We want to build substitutions in terms of Derived.foo()'s |
| 459 | + // generic signature: |
| 460 | + // |
| 461 | + // <T2, U2 where T2 : Q> |
| 462 | + // T2 := Bar |
| 463 | + // T2 : Q := Bar : Q |
| 464 | + // |
| 465 | + // The conformance Bar : Q is difficult to recover in the general case. |
| 466 | + // |
| 467 | + // Some combination of storing substitution maps in BoundGenericTypes |
| 468 | + // as well as for method overrides would solve this, but for now, just |
| 469 | + // punt to module lookup. |
| 470 | + if (substType->isTypeParameter()) |
| 471 | + return ProtocolConformanceRef(proto); |
| 472 | + |
| 473 | + return swift::lookupConformance(substType, proto); |
| 474 | + }); |
| 475 | +} |
| 476 | + |
389 | 477 | // Start with the substitutions from the apply.
|
390 | 478 | // Try to propagate them to find out the real substitutions required
|
391 | 479 | // to invoke the method.
|
@@ -440,13 +528,11 @@ getSubstitutionsForCallee(SILModule &module, CanSILFunctionType baseCalleeType,
|
440 | 528 |
|
441 | 529 | auto baseCalleeSig = baseCalleeType->getInvocationGenericSignature();
|
442 | 530 |
|
443 |
| - return |
444 |
| - SubstitutionMap::combineSubstitutionMaps(baseSubMap, |
445 |
| - origSubMap, |
446 |
| - CombineSubstitutionMaps::AtDepth, |
447 |
| - baseDepth, |
448 |
| - origDepth, |
449 |
| - baseCalleeSig); |
| 531 | + return combineSubstitutionMaps(baseSubMap, |
| 532 | + origSubMap, |
| 533 | + baseDepth, |
| 534 | + origDepth, |
| 535 | + baseCalleeSig); |
450 | 536 | }
|
451 | 537 |
|
452 | 538 | // Return the new apply and true if a cast required CFG modification.
|
|
0 commit comments