Skip to content

Concrete type propagation using ProtocolConformanceAnalysis #17373

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

Merged
merged 1 commit into from
Aug 22, 2018

Conversation

rajbarik
Copy link
Contributor

Part 2 of #16739

This peephole optimization propagates concrete types for self arguments and rewrites witness methods using ProtocolConformanceAnalysis!

@rajbarik
Copy link
Contributor Author

@slavapestov Second PR for concrete type propagation of self arguments using ProtocolConformanceAnalysis, that was merged couple of days ago.

@@ -298,6 +312,20 @@ class SILCombiner :
WitnessMethodInst *WMI);
SILInstruction *propagateConcreteTypeOfInitExistential(FullApplySite AI);

/// Propagate concrete types from ProtocolConformanceAnalysis.
SILInstruction *propagateConcreteTypeFromPCA(FullApplySite AI);
Copy link
Contributor

Choose a reason for hiding this comment

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

"propagateSoleConformingType"


/// Internal method to prepare and check code for concrete type propagation
/// using ProtocolConformanceAnalysis via unchecked cast instructions.
bool prepareNCheckConcreteTypePropagationFromPCA(
Copy link
Contributor

Choose a reason for hiding this comment

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

"prepareAndCheckConcreteTypePropagation"

Maybe define a class with arguments?


/// Traverse ProtocolConformanceMapCache from ProtocolConformanceAnalysis
/// recursively to determine concrete type.
NominalTypeDecl *findSoleConformingTypeFromPCA(ProtocolDecl *Protocol);
Copy link
Contributor

Choose a reason for hiding this comment

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

"findSoleConformingType"

/// class, struct or enum type.
NominalTypeDecl *
SILCombiner::findSoleConformingTypeFromPCA(ProtocolDecl *Protocol) {
SmallVector<ProtocolDecl *, 16> PDWorkList;
Copy link
Contributor

Choose a reason for hiding this comment

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

All of this except for the CHA part should go into the protocol conformance analysis

return false;

/// Ignore already visited Apply sites.
if (VisitedAIForPCA.find(Apply) != VisitedAIForPCA.end())
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this introduce a use-after-free?

return false;

// Do not handle unbounded generics.
auto ElementType = NTD->getDeclaredType();
Copy link
Contributor

Choose a reason for hiding this comment

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

Better way to check: NTD->isGenericContext(). And move this into findSoleConformingTypeFromPCA()


SILValue Self = Apply.getSelfArgument();
auto *WMI = dyn_cast<WitnessMethodInst>(Apply.getCallee());
if (!WMI)
Copy link
Contributor

Choose a reason for hiding this comment

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

What if I'm calling a statically-dispatched protocol extension method?

extension P { func f() { ... } }

@@ -858,7 +1029,7 @@ SILInstruction *SILCombiner::propagateConcreteTypeOfInitExistential(
SILInstruction *InitExistential = findInitExistential(
Apply, Self, OpenedArchetype, OpenedArchetypeDef, isCopied);
if (!InitExistential)
return nullptr;
return propagateConcreteTypeFromPCA(Apply);
Copy link
Contributor

Choose a reason for hiding this comment

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

Move this to the callers of propagateConcreteTypeOfInitExistential()

// CHECK: integer_literal
// CHECK: ref_element_addr
// CHECK: open_existential_addr
// CHECK: witness_method
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you elaborate these witness_methods so its easier to read the test case

return false;

// Determine the sole conforming type.
auto *NTD = findSoleConformingTypeFromPCA(Protocol);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do this first, to avoid doing everything else

@slavapestov slavapestov self-assigned this Jun 27, 2018
@rajbarik rajbarik force-pushed the raj-cta branch 2 times, most recently from bb9fd48 to e0a80de Compare July 3, 2018 21:41
@rajbarik
Copy link
Contributor Author

rajbarik commented Jul 3, 2018

@atrick @slavapestov can you review this PR now? I have taken care of all the comments.

// Empty initilization of ConcreteExistentialInfo. This is used when the
// concrete type is determined via ProtocolConformanceAnalysis. The fields
// are populated during sil_combiner.
ConcreteExistentialInfo() {}
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of default initializing, can you pass around an Optional<ConcreteExistentialInfo>?

@@ -30,7 +30,7 @@ class NominalTypeWalker : public ASTWalker {

public:
NominalTypeWalker(ProtocolConformanceAnalysis::ProtocolConformanceMap
&ProtocolConformanceCache)
&ProtocolConformanceCache)
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary change?

ProtocolConformanceAnalysis::findSoleConformingType(ProtocolDecl *Protocol) {
SmallVector<ProtocolDecl *, 16> PDWorkList;
SmallPtrSet<ProtocolDecl *, 8> VisitedPDs;
SmallPtrSet<NominalTypeDecl *, 8> ConformanceSet;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this just be a NominalTypeDecl *?

/// class, struct or enum type.
NominalTypeDecl *
ProtocolConformanceAnalysis::findSoleConformingType(ProtocolDecl *Protocol) {
SmallVector<ProtocolDecl *, 16> PDWorkList;
Copy link
Contributor

Choose a reason for hiding this comment

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

Use 2 for the default size

if (!VisitedPDs.count(Proto))
PDWorkList.push_back(Proto);
} else { // Classes, Structs and Enums are added here.
ConformanceSet.insert(ConformingNTD);
Copy link
Contributor

Choose a reason for hiding this comment

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

Bail out here

if (WMI->use_empty())
eraseInstFromFunction(*WMI);
}
auto *NewAI = createApplyWithConcreteType(Apply, CEI, BuilderCtx);
Copy link
Contributor

Choose a reason for hiding this comment

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

Create a new overload of createApplyWithConcreteType() so you can share this block of code between here and SILCombiner::propagateConcreteTypeOfInitExistential()

@@ -711,7 +848,8 @@ SILCombiner::createApplyWithConcreteType(FullApplySite Apply,
}
// The apply can only be rewritten in terms of the concrete value if it is
// legal to pass that value as the self argument.
if (CEI.isCopied && !canReplaceCopiedSelf(Apply, CEI.InitExistential, DA))
if (CEI.InitExistential && CEI.isCopied &&
!canReplaceCopiedSelf(Apply, CEI.InitExistential, DA))
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@atrick suggested this: if (isCopied && (!InitExistential || !canReplaceCopiedSelf(Apply, InitExistential)
which seem reasonable.

if (!propagateConcreteTypeOfInitExistential(AI, WMI) &&
(WMI = dyn_cast<WitnessMethodInst>(AI->getCallee()))) {
// Propagate concrete type from ProtocolConformanceAnalysis.
propagateSoleConformingType(AI, WMI);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think if propagateConcreteTypeOfInitExistential() returned a boolean indicating if the WMI was replaced, you would only call propagateSoleConformingType() if it returned false, and not have to worry about getting the WMI out again

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK. Will create a new PR with propagateConcreteTypeOfInitExistential() returning true/false.

if (!propagateConcreteTypeOfInitExistential(AI, WMI) &&
(WMI = dyn_cast<WitnessMethodInst>(AI->getCallee()))) {
// Propagate concrete type from ProtocolConformanceAnalysis.
propagateSoleConformingType(AI, WMI);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

}
}

// case 5: Generic protocol -- should not optimize
Copy link
Contributor

Choose a reason for hiding this comment

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

Generic conforming type

@rajbarik
Copy link
Contributor Author

@atrick @slavapestov Any possibility of getting this review done? Thanks.


SILValue Self = Apply.getSelfArgument();
auto *PD = WMI->getLookupProtocol();
ConcreteExistentialInfo CEI(Apply.getSelfArgumentOperand(), true);
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it really makes sense to construct a fake, invalid ConcreteExistentialInfo, then fill in its fields here. It seems like this should be an alternate constructor.

@rajbarik
Copy link
Contributor Author

rajbarik commented Aug 1, 2018

@atrick Moved the code that separately populated ConcreteExistentialInfo as an alternative constructor for ConcreteExistentialInfo. Can you check and let me know if you have any other concerns?

Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

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

I don't really understand what's happening yet. Can you clarify some of the points below?

if ((CD = dyn_cast<ClassDecl>(NTD)) &&
(CD->getEffectiveAccess() == AccessLevel::Open ||
CHA->hasKnownDirectSubclasses(CD) ||
CHA->hasKnownIndirectSubclasses(CD))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Out of curiosity, how can a class have indirect subclasses without having direct subclasses?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My understanding was that they were disjoint sets. But looking at the code closely seems like Indirect Subclasses are derived from DirectSubClasses. So, check for hasKnownDirectSubClasses should suffice in this case.

ConcreteExistentialInfo(ConcreteExistentialInfo &) = delete;

/// We do not not need to check for InitExistential not being not null
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand the comment. Aren't you allowing InitExistential to be null when the concrete type was derived through analysis instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will rephrase the comment.

// findInitExistential for the argument.
isCopied = false;
OpenedArchetypeDef = Arg;
InitExistential = findInitExistential(ArgOperand, OpenedArchetype,
Copy link
Contributor

Choose a reason for hiding this comment

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

Can the returned InitExistential be nullptr? Please comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, InitExistential can be nullptr. Will update the comment. Thanks.

InitExistential = findInitExistential(ArgOperand, OpenedArchetype,
OpenedArchetypeDef, isCopied);

// If no InitExistential is found, check if the argument is already an opened
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm really confused now. The code below runs regardless of whether InitExistential was found or not. How is it related to InitExstential?

Copy link
Contributor

Choose a reason for hiding this comment

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

Dumb question: if the caller already knows the ConcreteType and Protocol, why do we need to bother looking for the InitExistential?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I still need the OpenedArchetypeDef to be able to cast it to the concrete type. findInitExistential helps me determine this OpenedArchetypeDef. For cases where OpenedArchetypeDef can not be found (because there was no InitExistential), then the code below does extra effort in trying to find if Arg is itself OpenedArcheTypeDef or AllocStackInst, in which case it determines the OpenedArcheTypeDef. I will update the comment. Let me know if this makes sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

That's the part I was missing. It almost looked like you could reuse the same constructor for both the current case and the CHA/PCA case but just pass in an optional ConcreteType in the later case.

ConcreteExistentialInfo::ConcreteExistentialInfo(
ProtocolConformanceAnalysis *PCA, ClassHierarchyAnalysis *CHA,
SILBuilder &Builder, ProtocolDecl *Protocol, FullApplySite Apply,
SILValue &Arg, Operand &ArgOperand) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem like a clean encapsulation anymore. Why can't the caller just pass in ConcreteType and Protocol when it can obtain those from its analyses? Why do you need to pass in PCA and CHA?

Apply, Arg, and ArgOperand all seem redundant. Why don't we just pass in a single openedUse (the open_existential_ref's use) just like the original constructor?

Also, the top-level comment on struct ConcreteExistentialInfo should be amended to mention new SIL patterns that we handle. Or move the existing comments onto the original constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason I wanted it this way is that I can create ConcreteExistentialInfo from another optimization #17366. I did not want code duplication later. May be for now, I will simplify the constructor as you suggested and worry about it later with a common interface for the other PR. Again, will update the comment.

@rajbarik
Copy link
Contributor Author

rajbarik commented Aug 3, 2018

@atrick @slavapestov Cleaned up the interfaces a bit. Please have a look now.

Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

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

Great. Just a few more comments...

isCopied = false;
OpenedArchetypeDef = Arg;
InitExistential = findInitExistential(ArgOperand, OpenedArchetype,
OpenedArchetypeDef, isCopied);
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the comments. If InitExistential is non-null, do you think it would be useful to assert that it's concrete type is the same as the passed in ConcreteType?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea!


// We have the open_existential; we still need the conformance.
auto ConformanceRef =
M.getSwiftModule()->lookupConformance(ConcreteType, Protocol);
Copy link
Contributor

Choose a reason for hiding this comment

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

We're generally not supposed to call SwiftModule::lookupConformance from the optimizer because the conformance hasn't necessarilly been type checked. In this case, I don't really see an alternative though. @slavapestov , do you have any suggestions? Are there certain conditions where we can say that it's safe to do this?

auto *URCI =
Builder.createUncheckedRefCast(OER->getLoc(), OER, ConcreteSILType);
OpenedArchetype = OER->getType().getASTType()->castTo<ArchetypeType>();
ConcreteValue = URCI;
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, this works, but it's kind of hacky because ConcreteExistentialInfo is supposed to be a mini-analysis that just summarizes all the various SIL patterns we may encounter where the common thread is that we have an open_existential as the self argument of an apply. It's confusing if an analysis utility also mutates the SIL. Rather than passing in a Builder, propagateSoleConformingType should be responsible for generating the cast that it needs. I think it's fine if you allow a valid ConcreteExistentialInfo to have an invalid ConcreteValue when InitExistential == nullptr.

So maybe you could remove ConcreteValue from the isValid and add an assert instead: !InitExistential || ConcreteValue

Then, in your new CHA/PCA case, you could use just use the existing ConcreteValue if an InitExistential is found without doing the cast. Would that make sense? If there's no InitExistential, then propagateSoleConformingType could generate the cast.

@rajbarik rajbarik force-pushed the raj-cta branch 2 times, most recently from 1b3ec63 to cc1638c Compare August 6, 2018 20:37
@rajbarik
Copy link
Contributor Author

rajbarik commented Aug 6, 2018

@atrick @slavapestov Done. Anything else?

Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

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

Looks great! Just one argument type to fix, and a side question for @slavapestov that doesn't need to hold up the merge.

// known ConcreteType and ProtocolDecl pair. It determines the
// OpenedArchetypeDef for the ArgOperand that will be used by unchecked_cast
// instructions to cast OpenedArchetypeDef to ConcreteType.
ConcreteExistentialInfo(Operand &ArgOperand, const CanType &ConcreteType,
Copy link
Contributor

Choose a reason for hiding this comment

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

The convention is to pass CanType by value:

, CanType ConcreteType,


// We have the open_existential; we still need the conformance.
auto ConformanceRef =
M.getSwiftModule()->lookupConformance(ConcreteType, Protocol);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm still curious what @slavapestov has to say about calling lookupConformance here. It seems like we should come up with some rules for when it's ok for the optimizer to do this and enforce it in the API.

Copy link
Contributor

Choose a reason for hiding this comment

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

In this case it's fine to call lookupConformance() -- there's no way for the type checker to anticipate a conformance is needed here and store it somewhere. However, the resulting conformance might be incomplete, which will cause problems later in IRGen if you try to use it.

So I would add a check for the conformance being complete.

Also please try to come up with a test case that would fail without this check. It will require the conforming type to be defined in another file, so that when you build in non-WMO mode, the type checker will not check the conformance.

Copy link
Contributor

Choose a reason for hiding this comment

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

... OK, but since this optimization only applies in WMO mode, you won't be able to get a test case. In that case, please just assert that the conformance is complete.

@rajbarik rajbarik force-pushed the raj-cta branch 2 times, most recently from bd61a1d to 9732bdf Compare August 7, 2018 21:25
Copy link
Contributor

@slavapestov slavapestov left a comment

Choose a reason for hiding this comment

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

Looks good, feel free to merge once you've addressed the other comments.

/// class, struct or enum type.
NominalTypeDecl *
ProtocolConformanceAnalysis::findSoleConformingType(ProtocolDecl *Protocol) {
SmallVector<ProtocolDecl *, 8> PDWorkList;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the result of this be cached?

PDWorkList.push_back(Protocol);
while (!PDWorkList.empty()) {
auto *PD = PDWorkList.pop_back_val();
// Protocols must have internal or lower access scopes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Just access, not access scope

}
VisitedPDs.insert(PD);
auto NTDList = getConformances(PD);
if (NTDList.empty())
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this check is necessary -- a for loop over an empty collection won't do much work.

Op.set(NewWMI);
}
if (WMI->use_empty())
eraseInstFromFunction(*WMI);
Copy link
Contributor

Choose a reason for hiding this comment

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

If it has other uses, they could also be replaced with NewWMI. In fact you could avoid passing in the Apply here, and look at all uses of the WMI instead.

// TO
// %4 = open_existential_ref %3 : $P to $@opened P
// %7 = unchecked_ref_cast %4 : $@opened P to $C
// %8 = class_method %7 : $C, #C.foo!1 : (C) -> () -> Int,
Copy link
Contributor

Choose a reason for hiding this comment

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

The actual replacement of the witness_method with class_method is done in the devirtualization pass, not this function. Also the SIL is just kind of hard to read. Can you instead just write a comment that says it replaces the witness_method instruction with one that has a concrete type, allowing other optimizations to devirtualize it later?


assert(CEI.ConcreteValue);

/// Replace the old WitnessMehod with a new one that has concrete type and
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: WitnessMehod


/// Determine the OpenedArchetype.
OpenedArchetype =
OpenedArchetypeDef->getType().getASTType()->castTo<ArchetypeType>();
Copy link
Contributor

Choose a reason for hiding this comment

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

OpenedArchetypeDef->getType().castTo<ArchetypeType>();


// We have the open_existential; we still need the conformance.
auto ConformanceRef =
M.getSwiftModule()->lookupConformance(ConcreteType, Protocol);
Copy link
Contributor

Choose a reason for hiding this comment

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

... OK, but since this optimization only applies in WMO mode, you won't be able to get a test case. In that case, please just assert that the conformance is complete.

@rajbarik
Copy link
Contributor Author

@atrick I believe you wrote the following test case in sil_combine_concrete_existential.swift. Turns out that my pass determines concrete type for p and makes the p.returnsOptionalIndirect() a direct call.

// The first apply has been devirtualized and inlined. The second remains unspecialized.
// CHECK-LABEL: sil @$S32sil_combine_concrete_existential37testWitnessReturnOptionalIndirectSelfyyF : $@convention(thin) () -> () {
// CHECK: switch_enum_addr %{{.*}} : $*Optional<@opened("{{.*}}") PPP>, case #Optional.some!enumelt.1: bb{{.*}}, case #Optional.none!enumelt: bb{{.*}}
// CHECK: [[O:%.*]] = open_existential_addr immutable_access %{{.*}} : $*PPP to $*@opened("{{.*}}") PPP
// CHECK: [[W:%.*]] = witness_method $@opened("{{.*}}") PPP, #PPP.returnsOptionalIndirect!1 : <Self where Self : PPP> (Self) -> () -> @dynamic_self Self?, [[O]] : $*@opened("{{.*}}") PPP : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
// CHECK: apply [[W]]<@opened("{{.*}}") PPP>(%{{.*}}, [[O]]) : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
// CHECK-LABEL: } // end sil function '$S32sil_combine_concrete_existential37testWitnessReturnOptionalIndirectSelfyyF'
public func testWitnessReturnOptionalIndirectSelf() {
  let p: PPP = S()
  p.returnsOptionalIndirect()?.returnsOptionalIndirect()
}

I have updated the test case by adding another unused struct so that S is not the SoleConformingType:

struct SS: PPP {
  func returnsOptionalIndirect() -> SS? {
    return self
  }
}

Let me know if you disagree.

@atrick
Copy link
Contributor

atrick commented Aug 14, 2018

@rajbarik thanks for fixing the test.


/// Determine the ExistentialConformances and SubstitutionMap.
auto ExistentialConformances = ArrayRef<ProtocolConformanceRef>(
ProtocolConformanceRef(ConcreteConformance));
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this a use-after-free? I would rely on the implicit conversion between T[] and ArrayRef<T> and just pass {ProtocolConformanceRef(ConcreteConformance)} as the parameter to SubstitutionMap::get below

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried this before and even now. I get the following error:

../Existential.cpp:378:21: error: call to 'get' is ambiguous
  ExistentialSubs = SubstitutionMap::get(ExistentialSig, {ConcreteType},
                    ^~~~~~~~~~~~~~~~~~~~
.../swift/include/swift/AST/SubstitutionMap.h:105:26: note: candidate function
  static SubstitutionMap get(GenericSignature *genericSig,
                         ^.../swift/include/swift/AST/SubstitutionMap.h:118:26: note: candidate function
  static SubstitutionMap get(GenericSignature *genericSig,
                         ^
1 error generated.

Code changed:

ExistentialSubs = SubstitutionMap::get(ExistentialSig, {ConcreteType},
                                         /*ExistentialConformances*/ {ProtocolConformanceRef(ConcreteConformance)});

@slavapestov
Copy link
Contributor

@swift-ci Please test

@slavapestov
Copy link
Contributor

@swift-ci Please test source compatibility

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - cc1638c2ef50a4f0ef357f5f9bd09430d1814799

@slavapestov
Copy link
Contributor

@swift-ci Please test source compatibility

@slavapestov
Copy link
Contributor

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - a5aef01496d233e6ac135e597c0e2141d7c4b452

@slavapestov
Copy link
Contributor

@rajbarik

/Users/buildnode/jenkins/workspace/swift-PR-osx/branch-master/swift/test/SILOptimizer/sil_combine_protocol_conf.swift:247:11: error: CHECK: expected string not found in input
15:46:57 // CHECK: load [[S11]] : $*Builtin.Int64
15:46:57           ^
15:46:57 <stdin>:1376:51: note: scanning from here
15:46:57  %8 = struct_element_addr %7 : $*Int, #Int._value // user: %9
15:46:57                                                   ^
15:46:57 <stdin>:1376:51: note: with variable "S11" equal to "%8"
15:46:57  %8 = struct_element_addr %7 : $*Int, #Int._value // user: %9
15:46:57                                                   ^
15:46:57 <stdin>:1377:7: note: possible intended match here
15:46:57  %9 = load %8 : $*Builtin.Int32 // user: %20
15:46:57       ^
15:46:57 
15:46:57 --
15:46:57 

Looks like you need to tweak the regex for 32 bit. Please run check-swift-validation-iphonesimulator-i386 locally.

@rajbarik
Copy link
Contributor Author

@slavapestov please run tests.

@slavapestov
Copy link
Contributor

@swift-ci Please test

1 similar comment
@slavapestov
Copy link
Contributor

@swift-ci Please test

@slavapestov slavapestov merged commit 42785be into swiftlang:master Aug 22, 2018
@gottesmm
Copy link
Contributor

@rajbarik +1! Congrats!

@rajbarik
Copy link
Contributor Author

@atrick @slavapestov Thanks a lot for all your help!

@atrick
Copy link
Contributor

atrick commented Aug 22, 2018

@rajbarik Thanks for keeping at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants