Skip to content

[Sema] NFC: refactor coerceToType() to use switch statments #22681

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
Feb 19, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 117 additions & 85 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6516,52 +6516,74 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
}
}

// Handle "from specific" coercions before "catch all" coercions.
auto desugaredFromType = fromType->getDesugaredType();
switch (desugaredFromType->getKind()) {
// Coercions from an lvalue: load or perform implicit address-of. We perform
// these coercions first because they are often the first step in a multi-step
// coercion.
if (auto fromLValue = fromType->getAs<LValueType>()) {
if (auto *toIO = toType->getAs<InOutType>()) {
// In an 'inout' operator like "i += 1", the operand is converted from
// an implicit lvalue to an inout argument.
assert(toIO->getObjectType()->isEqual(fromLValue->getObjectType()));
return cs.cacheType(new (tc.Context)
InOutExpr(expr->getStartLoc(), expr,
toIO->getObjectType(),
/*isImplicit*/ true));
}

return coerceToType(addImplicitLoadExpr(cs, expr), toType, locator);
case TypeKind::LValue: {
auto fromLValue = cast<LValueType>(desugaredFromType);
auto toIO = toType->getAs<InOutType>();
if (!toIO)
return coerceToType(addImplicitLoadExpr(cs, expr), toType, locator);

// In an 'inout' operator like "i += 1", the operand is converted from
// an implicit lvalue to an inout argument.
assert(toIO->getObjectType()->isEqual(fromLValue->getObjectType()));
return cs.cacheType(new (tc.Context) InOutExpr(expr->getStartLoc(), expr,
toIO->getObjectType(),
/*isImplicit*/ true));
}

// Coercions to tuple type.
if (auto toTuple = toType->getAs<TupleType>()) {
// Coerce from a tuple to a tuple.
if (auto fromTuple = fromType->getAs<TupleType>()) {
SmallVector<unsigned, 4> sources;
if (!computeTupleShuffle(fromTuple, toTuple, sources)) {
return coerceTupleToTuple(expr, fromTuple, toTuple,
locator, sources);
}
// Coerce from a tuple to a tuple.
case TypeKind::Tuple: {
auto fromTuple = cast<TupleType>(desugaredFromType);
auto toTuple = toType->getAs<TupleType>();
if (!toTuple)
break;
SmallVector<unsigned, 4> sources;
if (!computeTupleShuffle(fromTuple, toTuple, sources)) {
return coerceTupleToTuple(expr, fromTuple, toTuple,
locator, sources);
}
break;
}

case TypeKind::PrimaryArchetype:
case TypeKind::OpenedArchetype:
case TypeKind::NestedArchetype:
if (!cast<ArchetypeType>(desugaredFromType)->requiresClass())
break;
LLVM_FALLTHROUGH;

// Coercion from a subclass to a superclass.
//
// FIXME: Can we rig things up so that we always have a Superclass
// conversion restriction in this case?
if (fromType->mayHaveSuperclass() &&
toType->getClassOrBoundGenericClass()) {
case TypeKind::DynamicSelf:
case TypeKind::BoundGenericClass:
case TypeKind::Class: {
if (!toType->getClassOrBoundGenericClass())
break;
for (auto fromSuperClass = fromType->getSuperclass();
fromSuperClass;
fromSuperClass = fromSuperClass->getSuperclass()) {
if (fromSuperClass->isEqual(toType)) {
return coerceSuperclass(expr, toType, locator);
}
}
break;
}

// Coercions to function type.
if (auto toFunc = toType->getAs<FunctionType>()) {
// Coercion from one function type to another, this produces a
// FunctionConversionExpr in its full generality.
case TypeKind::Function: {
auto fromFunc = cast<FunctionType>(desugaredFromType);
auto toFunc = toType->getAs<FunctionType>();
if (!toFunc)
break;

// Default argument generator must return escaping functions. Therefore, we
// leave an explicit escape to noescape cast here such that SILGen can skip
// the cast and emit a code for the escaping function.
Expand All @@ -6570,49 +6592,52 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
isInDefaultArgumentContext = (initalizerCtx->getInitializerKind() ==
InitializerKind::DefaultArgument);
auto toEI = toFunc->getExtInfo();
// Coercion from one function type to another, this produces a
// FunctionConversionExpr in its full generality.
if (auto fromFunc = fromType->getAs<FunctionType>()) {
assert(toType->is<FunctionType>());
// If we have a ClosureExpr, then we can safely propagate the 'no escape'
// bit to the closure without invalidating prior analysis.
auto fromEI = fromFunc->getExtInfo();
if (toEI.isNoEscape() && !fromEI.isNoEscape()) {
auto newFromFuncType = fromFunc->withExtInfo(fromEI.withNoEscape());
if (!isInDefaultArgumentContext &&
applyTypeToClosureExpr(cs, expr, newFromFuncType)) {
fromFunc = newFromFuncType->castTo<FunctionType>();
// Propagating the 'no escape' bit might have satisfied the entire
// conversion. If so, we're done, otherwise keep converting.
if (fromFunc->isEqual(toType))
return expr;
} else if (isInDefaultArgumentContext) {
// First apply the conversion *without* noescape attribute.
if (!newFromFuncType->isEqual(toType)) {
auto escapingToFuncTy =
toFunc->withExtInfo(toEI.withNoEscape(false));
maybeDiagnoseUnsupportedFunctionConversion(cs, expr, toFunc);
expr = cs.cacheType(new (tc.Context) FunctionConversionExpr(
expr, escapingToFuncTy));
}
// Apply an explict function conversion *only* for the escape to
// noescape conversion. This conversion will be stripped by the
// default argument generator. (We can't return a @noescape function)
auto newExpr = cs.cacheType(new (tc.Context)
FunctionConversionExpr(expr, toFunc));
return newExpr;
assert(toType->is<FunctionType>());
// If we have a ClosureExpr, then we can safely propagate the 'no escape'
// bit to the closure without invalidating prior analysis.
auto fromEI = fromFunc->getExtInfo();
if (toEI.isNoEscape() && !fromEI.isNoEscape()) {
auto newFromFuncType = fromFunc->withExtInfo(fromEI.withNoEscape());
if (!isInDefaultArgumentContext &&
applyTypeToClosureExpr(cs, expr, newFromFuncType)) {
fromFunc = newFromFuncType->castTo<FunctionType>();
// Propagating the 'no escape' bit might have satisfied the entire
// conversion. If so, we're done, otherwise keep converting.
if (fromFunc->isEqual(toType))
return expr;
} else if (isInDefaultArgumentContext) {
// First apply the conversion *without* noescape attribute.
if (!newFromFuncType->isEqual(toType)) {
auto escapingToFuncTy =
toFunc->withExtInfo(toEI.withNoEscape(false));
maybeDiagnoseUnsupportedFunctionConversion(cs, expr, toFunc);
expr = cs.cacheType(new (tc.Context) FunctionConversionExpr(
expr, escapingToFuncTy));
}
// Apply an explict function conversion *only* for the escape to
// noescape conversion. This conversion will be stripped by the
// default argument generator. (We can't return a @noescape function)
auto newExpr = cs.cacheType(new (tc.Context)
FunctionConversionExpr(expr, toFunc));
return newExpr;
}
}

maybeDiagnoseUnsupportedFunctionConversion(cs, expr, toFunc);
maybeDiagnoseUnsupportedFunctionConversion(cs, expr, toFunc);

return cs.cacheType(new (tc.Context)
FunctionConversionExpr(expr, toType));
}
return cs.cacheType(new (tc.Context)
FunctionConversionExpr(expr, toType));
}

// Coercions from metadata to objects.
if (auto fromMeta = fromType->getAs<AnyMetatypeType>()) {
// Coercions from one metatype to another.
case TypeKind::Metatype: {
if (auto toMeta = toType->getAs<MetatypeType>())
return cs.cacheType(new(tc.Context) MetatypeConversionExpr(expr, toMeta));
LLVM_FALLTHROUGH;
}
// Coercions from metatype to objects.
case TypeKind::ExistentialMetatype: {
auto fromMeta = cast<AnyMetatypeType>(desugaredFromType);
if (toType->isAnyObject()) {
assert(cs.getASTContext().LangOpts.EnableObjCInterop
&& "metatype-to-object conversion requires objc interop");
Expand Down Expand Up @@ -6648,39 +6673,46 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
new (tc.Context) ProtocolMetatypeToObjectExpr(expr, toType));
}
}
}

// Coercions from a type to an existential type.
if (toType->isAnyExistentialType()) {
return coerceExistential(expr, toType, locator);
break;
}

if (toType->getOptionalObjectType() &&
cs.getType(expr)->getOptionalObjectType()) {
return coerceOptionalToOptional(expr, toType, locator, typeFromPattern);
default:
break;
}

// "Catch all" coercions.
auto desugaredToType = toType->getDesugaredType();
switch (desugaredToType->getKind()) {
// Coercions from a type to an existential type.
case TypeKind::ExistentialMetatype:
case TypeKind::ProtocolComposition:
case TypeKind::Protocol: {
return coerceExistential(expr, toType, locator);

// Coercion to Optional<T>.
if (auto toGenericType = toType->getAs<BoundGenericType>()) {
if (toGenericType->getDecl()->isOptionalDecl()) {
tc.requireOptionalIntrinsics(expr->getLoc());
case TypeKind::BoundGenericEnum: {
auto toGenericType = cast<BoundGenericEnumType>(desugaredToType);
if (!toGenericType->getDecl()->isOptionalDecl())
break;
tc.requireOptionalIntrinsics(expr->getLoc());

Type valueType = toGenericType->getGenericArgs()[0];
expr = coerceToType(expr, valueType, locator);
if (!expr) return nullptr;
if (cs.getType(expr)->getOptionalObjectType())
return coerceOptionalToOptional(expr, toType, locator, typeFromPattern);

auto *result =
cs.cacheType(new (tc.Context) InjectIntoOptionalExpr(expr, toType));
diagnoseOptionalInjection(result);
return result;
}
Type valueType = toGenericType->getGenericArgs()[0];
expr = coerceToType(expr, valueType, locator);
if (!expr) return nullptr;

auto *result =
cs.cacheType(new (tc.Context) InjectIntoOptionalExpr(expr, toType));
diagnoseOptionalInjection(result);
return result;
}
}

// Coercion from one metatype to another.
if (fromType->is<MetatypeType>() &&
toType->is<MetatypeType>()) {
auto toMeta = toType->castTo<MetatypeType>();
return cs.cacheType(new (tc.Context) MetatypeConversionExpr(expr, toMeta));
default:
break;
}

// Unresolved types come up in diagnostics for lvalue and inout types.
Expand Down