Resolve type(of:) by overload resolution rather than parse hackery.

`type(of:)` has behavior whose type isn't directly representable in Swift's type system, since it produces both concrete and existential metatypes. In Swift 3 we put in a parser hack to turn `type(of: <expr>)` into a DynamicTypeExpr, but this effectively made `type(of:)` a reserved name. It's a bit more principled to put `Swift.type(of:)` on the same level as other declarations, even with its special-case type system behavior, and we can do this by special-casing the type system we produce during overload resolution if `Swift.type(of:)` shows up in an overload set. This also lays groundwork for handling other declarations we want to ostensibly behave like normal declarations but with otherwise inexpressible types, viz. `withoutActuallyEscaping` from SE-0110.
This commit is contained in:
Joe Groff
2016-12-19 17:01:17 -08:00
parent 474096b9cb
commit 1889fde228
11 changed files with 236 additions and 14 deletions

View File

@@ -1319,18 +1319,64 @@ void ConstraintSystem::addOverloadSet(Type boundType,
addDisjunctionConstraint(overloads, locator, ForgetChoice, favoredChoice);
}
/// If we're resolving an overload set with a decl that has special type
/// checking semantics, set up the special-case type system and return true;
/// otherwise return false.
static bool
resolveOverloadForDeclWithSpecialTypeCheckingSemantics(ConstraintSystem &CS,
ConstraintLocator *locator,
Type boundType,
OverloadChoice choice,
Type &refType,
Type &openedFullType) {
assert(choice.getKind() == OverloadChoiceKind::Decl);
switch (CS.TC.getDeclTypeCheckingSemantics(choice.getDecl())) {
case DeclTypeCheckingSemantics::Normal:
return false;
case DeclTypeCheckingSemantics::TypeOf:
// Proceed with a "DynamicType" operation. This produces an existential
// metatype from existentials, or a concrete metatype from non-
// existentials (as seen from the current abstraction level), which can't
// be expressed in the type system currently.
auto input = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument), 0);
auto output = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult), 0);
auto inputArg = TupleTypeElt(input, CS.getASTContext().getIdentifier("of"));
auto inputTuple = TupleType::get(inputArg, CS.getASTContext());
CS.addConstraint(ConstraintKind::DynamicTypeOf, output, input,
CS.getConstraintLocator(locator, ConstraintLocator::RvalueAdjustment));
refType = FunctionType::get(inputTuple, output);
openedFullType = refType;
return true;
}
}
void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
Type boundType,
OverloadChoice choice) {
// Determine the type to which we'll bind the overload set's type.
Type refType;
Type openedFullType;
switch (choice.getKind()) {
case OverloadChoiceKind::DeclViaBridge:
switch (auto kind = choice.getKind()) {
case OverloadChoiceKind::Decl:
// If we refer to a top-level decl with special type-checking semantics,
// handle it now.
if (resolveOverloadForDeclWithSpecialTypeCheckingSemantics(
*this, locator, boundType, choice, refType, openedFullType))
break;
SWIFT_FALLTHROUGH;
case OverloadChoiceKind::DeclViaBridge:
case OverloadChoiceKind::DeclViaDynamic:
case OverloadChoiceKind::DeclViaUnwrappedOptional:
case OverloadChoiceKind::TypeDecl: {
bool isTypeReference = choice.getKind() == OverloadChoiceKind::TypeDecl;
bool isDynamicResult
= choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
@@ -1414,7 +1460,6 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
}
break;
}
assert(!refType->hasTypeParameter() && "Cannot have a dependent type here");
// If we're binding to an init member, the 'throws' need to line up between