mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user