-
Notifications
You must be signed in to change notification settings - Fork 10.6k
[SE-0042][AST/Sema/SILGen] Flattening the function type of unapplied method references #3836
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
Changes from all commits
5d55dc1
3b015dd
1022d8c
4f5a5f5
9482e2a
269516a
2a61f17
05c4782
2f36e11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2297,6 +2297,16 @@ class AnyFunctionType : public TypeBase { | |
| return getExtInfo().throws(); | ||
| } | ||
|
|
||
| unsigned getCurryLevel() const { | ||
|
||
| unsigned Level = 0; | ||
| const AnyFunctionType *function = this; | ||
| while ((function = function->getResult()->getAs<AnyFunctionType>())) | ||
| ++Level; | ||
| return Level; | ||
| } | ||
|
|
||
| AnyFunctionType *getUncurriedFunction(); | ||
|
|
||
| /// Returns a new function type exactly like this one but with the ExtInfo | ||
| /// replaced. | ||
| AnyFunctionType *withExtInfo(ExtInfo info) const; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3131,6 +3131,32 @@ AnyFunctionType *AnyFunctionType::withExtInfo(ExtInfo info) const { | |
| llvm_unreachable("unhandled function type"); | ||
| } | ||
|
|
||
| AnyFunctionType *AnyFunctionType::getUncurriedFunction() { | ||
|
||
| assert(getCurryLevel() > 0 && "nothing to uncurry"); | ||
|
|
||
| auto innerFunction = getResult()->castTo<AnyFunctionType>(); | ||
| SmallVector<TupleTypeElt, 4> params{getInput()->getDesugaredType()}; | ||
|
|
||
| if (auto tuple = dyn_cast<TupleType>(innerFunction->getInput().getPointer())) | ||
| params.append(tuple->getElements().begin(), tuple->getElements().end()); | ||
| else | ||
| params.push_back(innerFunction->getInput()->getDesugaredType()); | ||
|
|
||
| auto inputType = TupleType::get(params, getASTContext()); | ||
| auto extInfo = | ||
| innerFunction->getExtInfo().withRepresentation(getRepresentation()); | ||
|
|
||
| if (auto generic = getAs<GenericFunctionType>()) | ||
| return GenericFunctionType::get(generic->getGenericSignature(), inputType, | ||
| innerFunction->getResult(), extInfo); | ||
|
|
||
| if (auto poly = getAs<PolymorphicFunctionType>()) | ||
| return PolymorphicFunctionType::get(inputType, innerFunction->getResult(), | ||
| &poly->getGenericParams(), extInfo); | ||
|
|
||
| return FunctionType::get(inputType, innerFunction->getResult(), extInfo); | ||
| } | ||
|
|
||
| FunctionType *FunctionType::get(Type Input, Type Result, | ||
| const ExtInfo &Info) { | ||
| auto properties = getFunctionRecursiveProperties(Input, Result); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1232,6 +1232,13 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> { | |
| } | ||
|
|
||
| void visitFunctionConversionExpr(FunctionConversionExpr *e) { | ||
| // If this is a flattening function conversion, emit the expression | ||
| // directly. | ||
| if (e->isFlattening()) { | ||
|
||
| visitExpr(e); | ||
| return; | ||
| } | ||
|
|
||
| // FIXME: Check whether this function conversion requires us to build a | ||
| // thunk. | ||
| visit(e->getSubExpr()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1460,6 +1460,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction | |
| ManagedValue emitTransformedValue(SILLocation loc, ManagedValue input, | ||
| CanType inputType, | ||
| CanType outputType, | ||
| bool isFlattening = false, | ||
|
||
| SGFContext ctx = SGFContext()); | ||
|
|
||
| /// Most general form of the above. | ||
|
|
@@ -1468,6 +1469,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction | |
| CanType inputSubstType, | ||
| AbstractionPattern outputOrigType, | ||
| CanType outputSubstType, | ||
| bool isFlattening = false, | ||
| SGFContext ctx = SGFContext()); | ||
| RValue emitTransformedValue(SILLocation loc, RValue &&input, | ||
| AbstractionPattern inputOrigType, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -112,9 +112,11 @@ namespace { | |
| private: | ||
| SILGenFunction &SGF; | ||
| SILLocation Loc; | ||
| bool Flattening; | ||
|
|
||
| public: | ||
| Transform(SILGenFunction &SGF, SILLocation loc) : SGF(SGF), Loc(loc) {} | ||
| Transform(SILGenFunction &SGF, SILLocation loc, bool flattening = false) | ||
| : SGF(SGF), Loc(loc), Flattening(flattening) {} | ||
| virtual ~Transform() = default; | ||
|
|
||
| /// Transform an arbitrary value. | ||
|
|
@@ -1252,7 +1254,7 @@ namespace { | |
| return SGF.emitTransformedValue(Loc, input, | ||
| inputOrigType, inputSubstType, | ||
| outputOrigType, outputSubstType, | ||
| context); | ||
| /*isFlattening=*/false, context); | ||
| } | ||
|
|
||
| /// Force the given result into the given initialization. | ||
|
|
@@ -2177,7 +2179,7 @@ void ResultPlanner::execute(ArrayRef<SILValue> innerDirectResults, | |
| Gen.emitTransformedValue(Loc, innerResult, | ||
| op.InnerOrigType, op.InnerSubstType, | ||
| op.OuterOrigType, op.OuterSubstType, | ||
| outerResultCtxt); | ||
| /*isFlattening=*/false, outerResultCtxt); | ||
|
|
||
| // If the outer is indirect, force it into the context. | ||
| if (outerIsIndirect) { | ||
|
|
@@ -2269,26 +2271,72 @@ void ResultPlanner::execute(ArrayRef<SILValue> innerDirectResults, | |
| /// \param inputSubstType Formal AST type of function value being thunked | ||
| /// \param outputOrigType Abstraction pattern of the thunk | ||
| /// \param outputSubstType Formal AST type of the thunk | ||
| static void buildThunkBody(SILGenFunction &gen, SILLocation loc, | ||
| AbstractionPattern inputOrigType, | ||
| CanAnyFunctionType inputSubstType, | ||
| AbstractionPattern outputOrigType, | ||
| CanAnyFunctionType outputSubstType) { | ||
| static void buildThunkBody( | ||
| SILGenFunction &gen, SILLocation loc, bool isFlattening, | ||
| AbstractionPattern inputOrigType, CanAnyFunctionType inputSubstType, | ||
| AbstractionPattern outputOrigType, CanAnyFunctionType outputSubstType) { | ||
| PrettyStackTraceSILFunction stackTrace("emitting reabstraction thunk in", | ||
| &gen.F); | ||
| auto thunkType = gen.F.getLoweredFunctionType(); | ||
|
|
||
| FullExpr scope(gen.Cleanups, CleanupLocation::get(loc)); | ||
|
|
||
| SmallVector<ManagedValue, 8> params; | ||
| SmallVector<ManagedValue, 8> paramsBuffer; | ||
| // TODO: Could accept +0 arguments here when forwardFunctionArguments/ | ||
| // emitApply can. | ||
| gen.collectThunkParams(loc, params, /*allowPlusZero*/ false); | ||
|
|
||
| ManagedValue fnValue = params.pop_back_val(); | ||
| gen.collectThunkParams(loc, paramsBuffer, /*allowPlusZero*/ false); | ||
| ManagedValue fnValue = paramsBuffer.pop_back_val(); | ||
| auto fnType = fnValue.getType().castTo<SILFunctionType>(); | ||
| assert(!fnType->isPolymorphic()); | ||
| auto argTypes = fnType->getParameters(); | ||
|
|
||
| ArrayRef<ManagedValue> params(paramsBuffer); | ||
|
||
| if (isFlattening) { | ||
| // Flatten an instance function type. | ||
| assert( | ||
| inputSubstType->getCurryLevel() - outputSubstType->getCurryLevel() == 1 && | ||
| "Invalid (un)currying"); | ||
|
|
||
| SmallVector<SILValue, 1> selfArg; | ||
| forwardFunctionArguments(gen, loc, fnType, params.front(), selfArg); | ||
| auto inner = gen.emitApplyWithRethrow(loc, fnValue.forward(gen), | ||
| /*substFnType*/ fnValue.getType(), | ||
| /*substitutions*/ {}, selfArg); | ||
|
|
||
| // For the next steps update the variables by dropping the already applied | ||
| // first parameter (`self`) | ||
| params = params.slice(1); | ||
| fnValue = ManagedValue::forUnmanaged(inner); | ||
| fnType = fnValue.getType().castTo<SILFunctionType>(); | ||
| argTypes = fnType->getParameters(); | ||
| inputOrigType = inputOrigType.getFunctionResultType(); | ||
| inputSubstType = cast<AnyFunctionType>(inputSubstType.getResult()); | ||
|
|
||
| Type newOrigInput, newSubstInput; | ||
| auto origFunction = cast<AnyFunctionType>(outputOrigType.getType()); | ||
| if (auto origInput = dyn_cast<TupleType>(origFunction.getInput())) { | ||
| auto substInput = cast<TupleType>(outputSubstType.getInput()); | ||
| assert(origInput->getNumElements() == substInput->getNumElements() && | ||
| "invalid premise"); | ||
| newOrigInput = TupleType::get(origInput->getElements().slice(1), | ||
| gen.getASTContext()); | ||
| newSubstInput = TupleType::get(substInput->getElements().slice(1), | ||
| gen.getASTContext()); | ||
| } else { | ||
| // In this case `self` was the only parameter, which leaves us with an | ||
| // application of `Void` | ||
| assert(!dyn_cast<TupleType>(outputSubstType.getInput()) && | ||
| "invalid premise"); | ||
| newOrigInput = newSubstInput = TupleType::getEmpty(gen.getASTContext()); | ||
| } | ||
|
|
||
| outputOrigType = AbstractionPattern(CanFunctionType::get( | ||
| newOrigInput->getCanonicalType(), origFunction.getResult(), | ||
| origFunction->getExtInfo())); | ||
| outputSubstType = CanFunctionType::get(newSubstInput->getCanonicalType(), | ||
| outputSubstType.getResult(), | ||
| outputSubstType->getExtInfo()); | ||
| } | ||
|
|
||
| // Translate the argument values. Function parameters are | ||
| // contravariant: we want to switch the direction of transformation | ||
|
|
@@ -2419,14 +2467,12 @@ CanSILFunctionType SILGenFunction::buildThunkType( | |
| } | ||
|
|
||
| /// Create a reabstraction thunk. | ||
| static ManagedValue createThunk(SILGenFunction &gen, | ||
| SILLocation loc, | ||
| ManagedValue fn, | ||
| AbstractionPattern inputOrigType, | ||
| CanAnyFunctionType inputSubstType, | ||
| AbstractionPattern outputOrigType, | ||
| CanAnyFunctionType outputSubstType, | ||
| const TypeLowering &expectedTL) { | ||
| static ManagedValue createThunk( | ||
| SILGenFunction &gen, SILLocation loc, ManagedValue fn, | ||
| AbstractionPattern inputOrigType, CanAnyFunctionType inputSubstType, | ||
| AbstractionPattern outputOrigType, CanAnyFunctionType outputSubstType, | ||
| const TypeLowering &expectedTL, bool isFlattening) { | ||
|
|
||
| auto expectedType = expectedTL.getLoweredType().castTo<SILFunctionType>(); | ||
|
|
||
| // We can't do bridging here. | ||
|
|
@@ -2452,7 +2498,7 @@ static ManagedValue createThunk(SILGenFunction &gen, | |
| thunk->setContextGenericParams(gen.F.getContextGenericParams()); | ||
| SILGenFunction thunkSGF(gen.SGM, *thunk); | ||
| auto loc = RegularLocation::getAutoGeneratedLocation(); | ||
| buildThunkBody(thunkSGF, loc, | ||
| buildThunkBody(thunkSGF, loc, isFlattening, | ||
| inputOrigType, inputSubstType, | ||
| outputOrigType, outputSubstType); | ||
| } | ||
|
|
@@ -2494,7 +2540,7 @@ ManagedValue Transform::transformFunction(ManagedValue fn, | |
| return createThunk(SGF, Loc, fn, | ||
| inputOrigType, inputSubstType, | ||
| outputOrigType, outputSubstType, | ||
| expectedTL); | ||
| expectedTL, Flattening); | ||
|
||
| } | ||
|
|
||
| // We do not, conversion is trivial. | ||
|
|
@@ -2535,7 +2581,7 @@ SILGenFunction::emitOrigToSubstValue(SILLocation loc, ManagedValue v, | |
| return emitTransformedValue(loc, v, | ||
| origType, substType, | ||
| AbstractionPattern(substType), substType, | ||
| ctxt); | ||
| /*isFlattening=*/false, ctxt); | ||
| } | ||
|
|
||
| /// Given a value with the abstraction patterns of the original formal | ||
|
|
@@ -2561,7 +2607,7 @@ SILGenFunction::emitSubstToOrigValue(SILLocation loc, ManagedValue v, | |
| return emitTransformedValue(loc, v, | ||
| AbstractionPattern(substType), substType, | ||
| origType, substType, | ||
| ctxt); | ||
| /*isFlattening=*/false, ctxt); | ||
| } | ||
|
|
||
| /// Given a value with the abstraction patterns of the substituted | ||
|
|
@@ -2594,10 +2640,12 @@ ManagedValue | |
| SILGenFunction::emitTransformedValue(SILLocation loc, ManagedValue v, | ||
| CanType inputType, | ||
| CanType outputType, | ||
| bool isFlattening, | ||
| SGFContext ctxt) { | ||
| return emitTransformedValue(loc, v, | ||
| AbstractionPattern(inputType), inputType, | ||
| AbstractionPattern(outputType), outputType); | ||
| AbstractionPattern(outputType), outputType, | ||
| isFlattening, ctxt); | ||
| } | ||
|
|
||
| ManagedValue | ||
|
|
@@ -2606,8 +2654,9 @@ SILGenFunction::emitTransformedValue(SILLocation loc, ManagedValue v, | |
| CanType inputSubstType, | ||
| AbstractionPattern outputOrigType, | ||
| CanType outputSubstType, | ||
| bool isFlattening, | ||
| SGFContext ctxt) { | ||
| return Transform(*this, loc).transform(v, | ||
| return Transform(*this, loc, isFlattening).transform(v, | ||
| inputOrigType, | ||
| inputSubstType, | ||
| outputOrigType, | ||
|
|
||
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.
Might be better to make this its own type of Expr
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.
Thought about this as well, but there's exactly one place where we set this flag …
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.
Right, so that place can make the new Expr type instead. These really are not function conversions...