Skip to content

Commit 29446b3

Browse files
committed
Implicit conversions as initialisers.
1 parent b3ea383 commit 29446b3

File tree

10 files changed

+126
-3
lines changed

10 files changed

+126
-3
lines changed

include/swift/AST/ASTContext.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,18 @@ class ASTContext final {
366366
llvm::BumpPtrAllocator &
367367
getAllocator(AllocationArena arena = AllocationArena::Permanent) const;
368368

369+
llvm::DenseMap<NominalTypeDecl *,
370+
llvm::DenseMap<NominalTypeDecl *, ConstructorDecl *>> ConversionMap;
371+
369372
public:
373+
llvm::DenseMap<NominalTypeDecl *, ConstructorDecl *> *implicitConversionsFor(
374+
NominalTypeDecl *typeDecl, bool create) {
375+
auto map = ConversionMap.find(typeDecl);
376+
if (map != ConversionMap.end())
377+
return &map->getSecond();
378+
return create ? &ConversionMap[typeDecl] : nullptr;
379+
}
380+
370381
/// Allocate - Allocate memory from the ASTContext bump pointer.
371382
void *Allocate(unsigned long bytes, unsigned alignment,
372383
AllocationArena arena = AllocationArena::Permanent) const {

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3155,11 +3155,15 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
31553155
Bits.NominalTypeDecl.IsComputingSemanticMembers = false;
31563156
}
31573157

3158+
bool implicitConversionsComputed = false;
3159+
31583160
friend class ProtocolType;
31593161

31603162
public:
31613163
using GenericTypeDecl::getASTContext;
31623164

3165+
ConstructorDecl *implicitConversionTo(Type type);
3166+
31633167
SourceRange getBraces() const { return Braces; }
31643168

31653169
void setBraces(SourceRange braces) { Braces = braces; }

include/swift/Sema/Constraint.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ enum class ConversionRestrictionKind {
269269
/// Implicit conversion from a value of CGFloat type to a value of Double type
270270
/// via an implicit Double initializer call passing a CGFloat value.
271271
CGFloatToDouble,
272+
/// Implicit conversion where an init(implicit:) initializer is vailable
273+
ImplicitConversion,
272274
};
273275

274276
/// Specifies whether a given conversion requires the creation of a temporary

lib/AST/Decl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3839,6 +3839,7 @@ void NominalTypeDecl::addExtension(ExtensionDecl *extension) {
38393839
LastExtension->NextExtension.setPointer(extension);
38403840
LastExtension = extension;
38413841

3842+
implicitConversionsComputed = false;
38423843
addedExtension(extension);
38433844
}
38443845

lib/Sema/CSApply.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6907,6 +6907,56 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
69076907
finishApply(implicitInit, toType, callLocator, callLocator);
69086908
return implicitInit;
69096909
}
6910+
case ConversionRestrictionKind::ImplicitConversion: {
6911+
auto conversionKind = knownRestriction->second;
6912+
6913+
auto *argExpr = locator.trySimplifyToExpr();
6914+
assert(argExpr);
6915+
6916+
// Load the value for conversion.
6917+
argExpr = cs.coerceToRValue(argExpr);
6918+
6919+
auto *implicitInit =
6920+
CallExpr::createImplicit(ctx, TypeExpr::createImplicit(toType, ctx),
6921+
/*args=*/{argExpr},
6922+
/*argLabels=*/{ctx.Id_implicit});
6923+
6924+
cs.cacheExprTypes(implicitInit->getFn());
6925+
cs.setType(argExpr, fromType);
6926+
cs.setType(implicitInit->getArg(),
6927+
ParenType::get(cs.getASTContext(), fromType));
6928+
6929+
auto *callLocator = cs.getConstraintLocator(
6930+
implicitInit, LocatorPathElt::ImplicitConversion(conversionKind));
6931+
6932+
// HACK: Temporarily push the call expr onto the expr stack to make sure
6933+
// we don't try to prematurely close an existential when applying the
6934+
// curried member ref. This can be removed once existential opening is
6935+
// refactored not to rely on the shape of the AST prior to rewriting.
6936+
ExprStack.push_back(implicitInit);
6937+
SWIFT_DEFER { ExprStack.pop_back(); };
6938+
6939+
// We need to take information recorded for all conversions of this
6940+
// kind and move it to a specific location where restriction is applied.
6941+
if (01) {
6942+
auto *memberLoc = solution.getConstraintLocator(
6943+
callLocator, {ConstraintLocator::ApplyFunction,
6944+
ConstraintLocator::ConstructorMember});
6945+
6946+
auto overload = solution.getOverloadChoice(cs.getConstraintLocator(
6947+
ASTNode(), {LocatorPathElt::ImplicitConversion(conversionKind),
6948+
ConstraintLocator::ApplyFunction,
6949+
ConstraintLocator::ConstructorMember}));
6950+
6951+
solution.overloadChoices.insert({memberLoc, overload});
6952+
}
6953+
6954+
// Record the implicit call's parameter bindings and match direction.
6955+
solution.recordSingleArgMatchingChoice(callLocator);
6956+
6957+
finishApply(implicitInit, toType, callLocator, callLocator);
6958+
return implicitInit;
6959+
}
69106960
}
69116961
}
69126962

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6703,6 +6703,7 @@ void NonEphemeralConversionFailure::emitSuggestionNotes() const {
67036703
case ConversionRestrictionKind::ObjCTollFreeBridgeToCF:
67046704
case ConversionRestrictionKind::CGFloatToDouble:
67056705
case ConversionRestrictionKind::DoubleToCGFloat:
6706+
case ConversionRestrictionKind::ImplicitConversion:
67066707
llvm_unreachable("Expected an ephemeral conversion!");
67076708
}
67086709
}

lib/Sema/CSSimplify.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4980,22 +4980,54 @@ bool ConstraintSystem::repairFailures(
49804980
}
49814981

49824982
bool ConstraintSystem::toImmutablePossible(Type lhs, Type rhs) {
4983+
#if 1
4984+
if (auto nominal = lhs->getAnyNominal())
4985+
if (auto func = nominal->implicitConversionTo(rhs))
4986+
return true;
4987+
#else
49834988
if (rhs->isUnsafeRawPointer() && (lhs->isUnsafeMutableRawPointer() ||
4984-
lhs->isUnsafeMutablePointer() || lhs->isUnsafePointer()))
4989+
lhs->isUnsafeMutablePointer() || lhs->isUnsafePointer())) {
49854990
return true; // Unsafe[Mutable][Raw]Pointer -> UnsafeRawPointer
4991+
}
49864992
49874993
auto firstGenericArgument = [&](Type ty) -> CanType {
49884994
return dyn_cast<BoundGenericStructType>(ty->getCanonicalType())
49894995
->getGenericArgs()[0]->getCanonicalType();
49904996
};
49914997
49924998
if (lhs->isUnsafeMutablePointer() && rhs->isUnsafePointer() &&
4993-
firstGenericArgument(lhs) == firstGenericArgument(rhs))
4999+
firstGenericArgument(lhs) == firstGenericArgument(rhs)) {
5000+
rhs->dump();
5001+
lhs->dump();
49945002
return true; // UnsafeMutablePointer<Pointee> -> UnsafePointer<Pointee>
4995-
5003+
}
5004+
#endif
49965005
return false;
49975006
}
49985007

5008+
ConstructorDecl *NominalTypeDecl::implicitConversionTo(Type type) {
5009+
if (NominalTypeDecl *toNominal = type->getAnyNominal()) {
5010+
auto &ctx = getASTContext();
5011+
if (!toNominal->implicitConversionsComputed) {
5012+
auto implicitArgId = ctx.Id_implicit;
5013+
for (ExtensionDecl *extension : toNominal->getExtensions())
5014+
for (Decl *member : extension->getMembers())
5015+
if (ConstructorDecl *initDecl = dyn_cast<ConstructorDecl>(member)) {
5016+
ParameterList *args = initDecl->getParameters();
5017+
if (args->size() == 1 &&
5018+
args->get(0)->getBaseName().getIdentifier() == implicitArgId)
5019+
if (auto fromNominal = args->get(0)->getType()->getAnyNominal())
5020+
(*ctx.implicitConversionsFor(fromNominal, /*create*/true))
5021+
[toNominal] = initDecl;
5022+
}
5023+
toNominal->implicitConversionsComputed = true;
5024+
}
5025+
if (auto *exists = ctx.implicitConversionsFor(this, /*create*/false))
5026+
return (*exists)[toNominal];
5027+
}
5028+
return nullptr;
5029+
}
5030+
49995031
ConstraintSystem::TypeMatchResult
50005032
ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
50015033
TypeMatchOptions flags,
@@ -11200,6 +11232,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1120011232
{getConstraintLocator(locator), restriction});
1120111233
return SolutionKind::Solved;
1120211234
}
11235+
case ConversionRestrictionKind::ImplicitConversion:
11236+
return SolutionKind::Solved;
1120311237
}
1120411238

1120511239
llvm_unreachable("bad conversion restriction");

lib/Sema/Constraint.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,8 @@ StringRef swift::constraints::getName(ConversionRestrictionKind kind) {
562562
return "[CGFloat-to-Double]";
563563
case ConversionRestrictionKind::DoubleToCGFloat:
564564
return "[Double-to-CGFloat]";
565+
case ConversionRestrictionKind::ImplicitConversion:
566+
return "[Implicit-Conversion]";
565567
}
566568
llvm_unreachable("bad conversion restriction kind");
567569
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5130,6 +5130,7 @@ ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion,
51305130
case ConversionRestrictionKind::ObjCTollFreeBridgeToCF:
51315131
case ConversionRestrictionKind::CGFloatToDouble:
51325132
case ConversionRestrictionKind::DoubleToCGFloat:
5133+
case ConversionRestrictionKind::ImplicitConversion:
51335134
// @_nonEphemeral has no effect on these conversions, so treat them as all
51345135
// being non-ephemeral in order to allow their passing to an @_nonEphemeral
51355136
// parameter.

test/TypeCoercion/immutable_mutable.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22

33
import Swift
44

5+
extension UnsafeRawPointer {
6+
init(implicit: UnsafeMutableRawPointer) {
7+
self.init(implicit)
8+
}
9+
init(implicit: UnsafeMutablePointer<Pointee>) {
10+
self.init(implicit)
11+
}
12+
init(implicit: UnsafePointer<Pointee>) {
13+
self.init(implicit)
14+
}
15+
}
16+
extension UnsafePointer {
17+
init(implicit: UnsafeMutablePointer<Pointee>) {
18+
self.init(implicit)
19+
}
20+
}
21+
522
let optionalMutableRawPointer = UnsafeMutableRawPointer(bitPattern: -3)
623
let mutableRawPointer = optionalMutableRawPointer!
724
let immutable: UnsafeRawPointer = mutableRawPointer

0 commit comments

Comments
 (0)