Skip to content

Plumb Through Parameterized Protocol Existentials #41743

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 8 commits into from
Mar 9, 2022

Conversation

CodaFi
Copy link
Contributor

@CodaFi CodaFi commented Mar 9, 2022

Unblock most of the statics and the lowering for the static side of parameterized protocol existentials. Practically, this implements any P<T> for P a parameterized protocol type (as in #41640). It also unblocks any P<some Q>, though there's some representational issues that are not resolved in this PR - I will tackle them when opened existentials and their signatures are refactored to use a side substitution map.

CodaFi added 7 commits March 8, 2022 22:00
Add deep equality typing rules for

P =~= Q, T == X, U == Y, V == Z, ...
--------------------------------
P<T, U, V, ...> == Q<X, Y, Z, ...>

Also add existential matching rules to discharge the constraints on parameterized protocols against concrete types. e.g.

class C: P { typealias T = Int }
func foo<T>(_ x: P<T>) {}
foo(C())

Should cause T to unify against C.T = Int
Represent this in much the same way that collections do by creating an opaque value representing the source argument, and a conversion expression representing the destination argument.
@CodaFi CodaFi changed the title Plumb Through Parameterized Protocols Plumb Through Parameterized Protocol Existentials Mar 9, 2022
The problem is that we currenly cannot represent the generic signature of
values of type `any P<some P>`. This is because we wind up producing

<Self where Self : P, Self.T == (some P)>

What we'd like to do in the future is erase the errant (some P) with
a fresh generic parameter and keep a substitution map on the side that
records the opaque type constraint. Something like

<Self, Opaque1 where Self : P, Opaque1 : P, Self.T == Opaque1> where Opaque1 == (some P)
@CodaFi CodaFi force-pushed the existential-dread branch from 054f47d to 0aead28 Compare March 9, 2022 19:49
@CodaFi
Copy link
Contributor Author

CodaFi commented Mar 9, 2022

@swift-ci smoke test

@CodaFi CodaFi merged commit 512ebc5 into swiftlang:main Mar 9, 2022
@CodaFi CodaFi deleted the existential-dread branch March 9, 2022 23:12
@@ -635,6 +635,7 @@ Types
type ::= protocol-list 'p' // existential type
type ::= protocol-list superclass 'Xc' // existential type with superclass
type ::= protocol-list 'Xl' // existential type with AnyObject
type ::= protocol-list 'y' (type* '_')* type* retroactive-conformance* 'Xp' // parameterized protocol type
Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer a more general mangling that could accommodate arbitrary requirements in the future.

@@ -3253,6 +3259,22 @@ NodePointer Demangler::demangleSpecialType() {
return createType(createWithChildren(Node::Kind::ExistentialMetatype,
MTR, Type));
}
case 'P': {
NodePointer RetroactiveConformances;
Copy link
Contributor

Choose a reason for hiding this comment

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

What are the retroactive conformances here for? any P<some Q>?

@@ -1445,7 +1445,7 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
T = existential->getConstraintType()->getCanonicalType();
}
llvm::StructType *type;
if (isa<ProtocolType>(T))
if (isa<ProtocolType>(T) || isa<ParameterizedProtocolType>(T))
type = IGM.createNominalType(T);
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a FIXME here or an assert, since this is wrong; the parametrized protocol type does not share metadata with the protocol type

@@ -1464,9 +1464,10 @@ class SubstFunctionTypePatternVisitor
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, t))
return gp;

assert(!pattern.getType()->hasTypeParameter()
assert(pattern.getType()->isExistentialType() ||
Copy link
Contributor

Choose a reason for hiding this comment

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

When is this violated?


// Use the requirements of any parameterized protocols to build out fake
// argument conversions that can be used to infer opaque types.
SmallVector<CollectionUpcastConversionExpr::ConversionPair, 4> argConversions;
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe CollectionUpcastConversionExpr::ConversionPair should be moved out?

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.

3 participants