Skip to content

Sema: Clean up CSApply for CGFloat <-> Double conversion #78957

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 4 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4544,7 +4544,8 @@ ERROR(try_assign_rhs_noncovering,none,
"'" TRY_KIND_SELECT(0) "' following assignment operator does not cover "
"everything to its right", (unsigned))

ERROR(broken_bool,none, "type 'Bool' is broken", ())
ERROR(broken_stdlib_type,none,
"standard library type '%0' is missing or broken; this is a compiler bug", (StringRef))

WARNING(inject_forced_downcast,none,
"treating a forced downcast to %0 as optional will never produce 'nil'",
Expand Down
1 change: 0 additions & 1 deletion include/swift/Sema/CSTrail.def
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ LOCATOR_CHANGE(RecordedOpenedExistentialType, OpenedExistentialTypes)
LOCATOR_CHANGE(RecordedPackExpansionEnvironment, PackExpansionEnvironments)
LOCATOR_CHANGE(RecordedDefaultedConstraint, DefaultedConstraints)
LOCATOR_CHANGE(ResolvedOverload, ResolvedOverloads)
LOCATOR_CHANGE(RecordedImplicitValueConversion, ImplicitValueConversions)
LOCATOR_CHANGE(RecordedArgumentList, ArgumentLists)
LOCATOR_CHANGE(RecordedImplicitCallAsFunctionRoot, ImplicitCallAsFunctionRoots)
LOCATOR_CHANGE(RecordedSynthesizedConformance, SynthesizedConformances)
Expand Down
26 changes: 6 additions & 20 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -1580,10 +1580,6 @@ class Solution {
/// The locators of \c Defaultable constraints whose defaults were used.
llvm::DenseSet<ConstraintLocator *> DefaultedConstraints;

/// Implicit value conversions applied for a given locator.
std::vector<std::pair<ConstraintLocator *, ConversionRestrictionKind>>
ImplicitValueConversions;

/// The node -> type mappings introduced by this solution.
llvm::DenseMap<ASTNode, Type> nodeTypes;

Expand Down Expand Up @@ -2368,11 +2364,6 @@ class ConstraintSystem {
llvm::DenseMap<ConstraintLocator *, MatchCallArgumentResult>
argumentMatchingChoices;

/// The set of implicit value conversions performed by the solver on
/// a current path to reach a solution.
llvm::SmallDenseMap<ConstraintLocator *, ConversionRestrictionKind, 2>
ImplicitValueConversions;

/// The worklist of "active" constraints that should be revisited
/// due to a change.
ConstraintList ActiveConstraints;
Expand Down Expand Up @@ -4608,16 +4599,15 @@ class ConstraintSystem {
inline bool isFailure() const { return Kind == SolutionKind::Error; }
inline bool isAmbiguous() const { return Kind == SolutionKind::Unsolved; }

static TypeMatchResult success(ConstraintSystem &cs) {
static TypeMatchResult success() {
return {SolutionKind::Solved};
}

static TypeMatchResult failure(ConstraintSystem &cs,
ConstraintLocatorBuilder location) {
static TypeMatchResult failure() {
return {SolutionKind::Error};
}

static TypeMatchResult ambiguous(ConstraintSystem &cs) {
static TypeMatchResult ambiguous() {
return {SolutionKind::Unsolved};
}

Expand Down Expand Up @@ -4722,15 +4712,15 @@ class ConstraintSystem {
ConstraintLocatorBuilder locator);

TypeMatchResult getTypeMatchSuccess() {
return TypeMatchResult::success(*this);
return TypeMatchResult::success();
}

TypeMatchResult getTypeMatchFailure(ConstraintLocatorBuilder locator) {
return TypeMatchResult::failure(*this, locator);
return TypeMatchResult::failure();
}

TypeMatchResult getTypeMatchAmbiguous() {
return TypeMatchResult::ambiguous(*this);
return TypeMatchResult::ambiguous();
}

public:
Expand Down Expand Up @@ -5047,10 +5037,6 @@ class ConstraintSystem {
TypeMatchOptions flags,
ConstraintLocatorBuilder locator);

/// Update ImplicitValueConversions and record a change in the trail.
void recordImplicitValueConversion(ConstraintLocator *locator,
ConversionRestrictionKind restriction);

/// Simplify a conversion constraint by applying the given
/// reduction rule, which is known to apply at the outermost level.
SolutionKind simplifyRestrictedConstraint(
Expand Down
108 changes: 40 additions & 68 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4162,7 +4162,7 @@ namespace {

// SIL-generation magically turns this into a Bool; make sure it can.
if (!ctx.getBoolBuiltinInitDecl()) {
ctx.Diags.diagnose(expr->getLoc(), diag::broken_bool);
ctx.Diags.diagnose(expr->getLoc(), diag::broken_stdlib_type, "Bool");
// Continue anyway.
}

Expand Down Expand Up @@ -4200,7 +4200,7 @@ namespace {
auto boolDecl = ctx.getBoolDecl();

if (!boolDecl) {
ctx.Diags.diagnose(SourceLoc(), diag::broken_bool);
ctx.Diags.diagnose(SourceLoc(), diag::broken_stdlib_type, "Bool");
}

cs.setType(isSomeExpr, boolDecl ? ctx.getBoolType() : Type());
Expand Down Expand Up @@ -5868,6 +5868,9 @@ static unsigned getOptionalEvaluationDepth(Expr *expr, Expr *target) {
depth += getOptionalEvaluationDepth(open->getSubExpr(),
open->getOpaqueValue());
expr = open->getExistentialValue();
} else if (auto call = dyn_cast<CallExpr>(expr)) {
// CGFloat <-> Double conversions lower to constructor calls.
expr = call->getArgs()->getExpr(0);

// Otherwise, look through implicit conversions.
} else {
Expand Down Expand Up @@ -7262,77 +7265,46 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,

case ConversionRestrictionKind::CGFloatToDouble:
case ConversionRestrictionKind::DoubleToCGFloat: {
auto conversionKind = knownRestriction->second;

auto shouldUseCoercedExpr = [&]() {
// If conversion wraps the whole body of a single-expression closure,
// let's use the passed-in expression since the closure itself doesn't
// get updated until coercion is done.
if (locator.endsWith<LocatorPathElt::ClosureBody>())
return true;

// Contextual type locator always uses the original version of
// expression (before any coercions have been applied) because
// otherwise it wouldn't be possible to find the overload choice.
if (locator.endsWith<LocatorPathElt::ContextualType>())
return true;

// In all other cases use the expression associated with locator.
return false;
};

auto *argExpr =
shouldUseCoercedExpr() ? expr : locator.trySimplifyToExpr();
assert(argExpr);

// Source requires implicit conversion to match destination
// type but the conversion itself is recorded on assignment.
if (auto *assignment = dyn_cast<AssignExpr>(argExpr))
argExpr = assignment->getSrc();

// Load the value for conversion.
argExpr = cs.coerceToRValue(argExpr);

auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {argExpr});
auto *implicitInit = CallExpr::createImplicit(
ctx, TypeExpr::createImplicit(toType, ctx), argList);

cs.cacheExprTypes(implicitInit->getFn());
cs.setType(argExpr, fromType);

auto *callLocator = cs.getConstraintLocator(
implicitInit, LocatorPathElt::ImplicitConversion(conversionKind));

// HACK: Temporarily push the call expr onto the expr stack to make sure
// we don't try to prematurely close an existential when applying the
// curried member ref. This can be removed once existential opening is
// refactored not to rely on the shape of the AST prior to rewriting.
ExprStack.push_back(implicitInit);
SWIFT_DEFER { ExprStack.pop_back(); };

// We need to take information recorded for all conversions of this
// kind and move it to a specific location where restriction is applied.
{
auto *memberLoc = solution.getConstraintLocator(
callLocator, {ConstraintLocator::ApplyFunction,
ConstraintLocator::ConstructorMember});

ConstraintLocator *baseLoc =
cs.getImplicitValueConversionLocator(locator, conversionKind);
DeclName name(ctx, DeclBaseName::createConstructor(), Identifier());

ConstructorDecl *decl = nullptr;
SmallVector<ValueDecl *, 2> candidates;
dc->lookupQualified(toType->getAnyNominal(),
DeclNameRef(name), SourceLoc(),
NL_QualifiedDefault, candidates);
for (auto *candidate : candidates) {
auto *ctor = cast<ConstructorDecl>(candidate);
auto fnType = ctor->getMethodInterfaceType()->castTo<FunctionType>();
if (fnType->getNumParams() == 1 &&
fnType->getParams()[0].getPlainType()->isEqual(fromType) &&
fnType->getResult()->isEqual(toType)) {
decl = ctor;
break;
}
}

auto overload =
solution.getOverloadChoice(solution.getConstraintLocator(
baseLoc, {ConstraintLocator::ApplyFunction,
ConstraintLocator::ConstructorMember}));
if (decl == nullptr) {
ctx.Diags.diagnose(expr->getLoc(), diag::broken_stdlib_type,
toType->getAnyNominal()->getName().str());
auto *errorExpr = new (ctx) ErrorExpr(SourceRange(), toType);
cs.setType(errorExpr, toType);

solution.overloadChoices.insert({memberLoc, overload});
return errorExpr;
}

// Record the implicit call's parameter bindings and match direction.
solution.recordSingleArgMatchingChoice(callLocator);
auto *ctorRefExpr = new (ctx) DeclRefExpr(decl, DeclNameLoc(), /*Implicit=*/true);
ctorRefExpr->setType(decl->getInterfaceType());
auto *typeExpr = TypeExpr::createImplicit(toType, ctx);
auto *innerCall = ConstructorRefCallExpr::create(ctx, ctorRefExpr, typeExpr,
decl->getMethodInterfaceType());
cs.cacheExprTypes(innerCall);

auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {cs.coerceToRValue(expr)});
auto *outerCall = CallExpr::createImplicit(ctx, innerCall, argList);
outerCall->setType(toType);
cs.setType(outerCall, toType);

finishApply(implicitInit, toType, callLocator, callLocator);
return implicitInit;
return outerCall;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2683,7 +2683,7 @@ namespace {
auto boolDecl = ctx.getBoolDecl();

if (!boolDecl) {
ctx.Diags.diagnose(SourceLoc(), diag::broken_bool);
ctx.Diags.diagnose(SourceLoc(), diag::broken_stdlib_type, "Bool");
return Type();
}

Expand Down
84 changes: 17 additions & 67 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7646,6 +7646,22 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}
}

if (kind == ConstraintKind::BindToPointerType) {
if (desugar2->isEqual(getASTContext().TheEmptyTupleType))
return getTypeMatchSuccess();
}

if (kind == ConstraintKind::BindParam) {
if (auto *iot = dyn_cast<InOutType>(desugar1)) {
if (auto *lvt = dyn_cast<LValueType>(desugar2)) {
return matchTypes(iot->getObjectType(), lvt->getObjectType(),
ConstraintKind::Bind, subflags,
locator.withPathElement(
ConstraintLocator::LValueConversion));
}
}
}

if (kind >= ConstraintKind::Conversion) {
// An lvalue of type T1 can be converted to a value of type T2 so long as
// T1 is convertible to T2 (by loading the value). Note that we cannot get
Expand Down Expand Up @@ -7777,7 +7793,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}

// Special implicit nominal conversions.
if (!type1->is<LValueType>() && kind >= ConstraintKind::Subtype) {
if (!type1->is<LValueType>()) {
// Array -> Array.
if (desugar1->isArray() && desugar2->isArray()) {
conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayUpcast);
Expand All @@ -7793,11 +7809,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}
}

if (kind == ConstraintKind::BindToPointerType) {
if (desugar2->isEqual(getASTContext().TheEmptyTupleType))
return getTypeMatchSuccess();
}

if (kind >= ConstraintKind::Conversion) {
// It is never legal to form an autoclosure that results in these
// implicit conversions to pointer types.
Expand Down Expand Up @@ -8054,17 +8065,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}
}

if (kind == ConstraintKind::BindParam) {
if (auto *iot = dyn_cast<InOutType>(desugar1)) {
if (auto *lvt = dyn_cast<LValueType>(desugar2)) {
return matchTypes(iot->getObjectType(), lvt->getObjectType(),
ConstraintKind::Bind, subflags,
locator.withPathElement(
ConstraintLocator::LValueConversion));
}
}
}

// Matching types where one side is a pack expansion and the other is not
// means a pack expansion was used where it isn't supported.
if (type1->is<PackExpansionType>() != type2->is<PackExpansionType>()) {
Expand Down Expand Up @@ -14263,17 +14263,6 @@ void ConstraintSystem::addRestrictedConstraint(
TMF_GenerateConstraints, locator);
}

void ConstraintSystem::recordImplicitValueConversion(
ConstraintLocator *locator,
ConversionRestrictionKind restriction) {
bool inserted = ImplicitValueConversions.insert(
{getConstraintLocator(locator), restriction}).second;
ASSERT(inserted);

if (solverState)
recordChange(SolverTrail::Change::RecordedImplicitValueConversion(locator));
}

/// Given that we have a conversion constraint between two types, and
/// that the given constraint-reduction rule applies between them at
/// the top level, apply it and generate any necessary recursive
Expand Down Expand Up @@ -14850,45 +14839,6 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
if (worseThanBestSolution())
return SolutionKind::Error;

auto *conversionLoc =
getImplicitValueConversionLocator(locator, restriction);

auto *applicationLoc =
getConstraintLocator(conversionLoc, ConstraintLocator::ApplyFunction);

auto *memberLoc = getConstraintLocator(
applicationLoc, ConstraintLocator::ConstructorMember);

// Allocate a single argument info to cover all possible
// Double <-> CGFloat conversion locations.
auto *argumentsLoc =
getConstraintLocator(conversionLoc, ConstraintLocator::ApplyArgument);

if (!ArgumentLists.count(argumentsLoc)) {
auto *argList = ArgumentList::createImplicit(
getASTContext(), {Argument(SourceLoc(), Identifier(), nullptr)},
/*firstTrailingClosureIndex=*/std::nullopt,
AllocationArena::ConstraintSolver);
recordArgumentList(argumentsLoc, argList);
}

auto *memberTypeLoc = getConstraintLocator(
applicationLoc, LocatorPathElt::ConstructorMemberType());

auto *memberTy = createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape);

addValueMemberConstraint(MetatypeType::get(type2, getASTContext()),
DeclNameRef(DeclBaseName::createConstructor()),
memberTy, DC,
FunctionRefInfo::doubleBaseNameApply(),
/*outerAlternatives=*/{}, memberLoc);

addConstraint(ConstraintKind::ApplicableFunction,
FunctionType::get({FunctionType::Param(type1)}, type2),
memberTy, applicationLoc);

ImplicitValueConversions.insert(
{getConstraintLocator(locator), restriction});
return SolutionKind::Solved;
}
}
Expand Down
12 changes: 0 additions & 12 deletions lib/Sema/CSSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,6 @@ Solution ConstraintSystem::finalize() {
solution.appliedPropertyWrappers.insert(appliedWrapper);
}

// Remember implicit value conversions.
for (const auto &valueConversion : ImplicitValueConversions) {
solution.ImplicitValueConversions.push_back(valueConversion);
}

// Remember argument lists.
for (const auto &argListMapping : ArgumentLists) {
solution.argumentLists.insert(argListMapping);
Expand Down Expand Up @@ -445,13 +440,6 @@ void ConstraintSystem::replaySolution(const Solution &solution,
}
}

for (auto &valueConversion : solution.ImplicitValueConversions) {
if (ImplicitValueConversions.count(valueConversion.first) == 0) {
recordImplicitValueConversion(valueConversion.first,
valueConversion.second);
}
}

// Register the argument lists.
for (auto &argListMapping : solution.argumentLists) {
if (ArgumentLists.count(argListMapping.first) == 0)
Expand Down
Loading