Skip to content

Commit 58f57d2

Browse files
committed
Moving to restrictions mechanism
1 parent 29446b3 commit 58f57d2

File tree

8 files changed

+96
-112
lines changed

8 files changed

+96
-112
lines changed

include/swift/AST/ASTContext.h

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

369-
llvm::DenseMap<NominalTypeDecl *,
370-
llvm::DenseMap<NominalTypeDecl *, ConstructorDecl *>> ConversionMap;
369+
llvm::DenseMap<TypeBase *, llvm::DenseMap<TypeBase *,
370+
SmallVector<ConstructorDecl *, 2>>> ImplicitConversionMap;
371371

372372
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;
373+
llvm::DenseMap<TypeBase *, SmallVector<ConstructorDecl *, 2>>
374+
*implicitConversionsTo(TypeBase *toType, bool create) {
375+
auto constructorsByFromType = ImplicitConversionMap.find(toType);
376+
if (constructorsByFromType != ImplicitConversionMap.end())
377+
return &constructorsByFromType->getSecond();
378+
return create ? &ImplicitConversionMap[toType] : nullptr;
379379
}
380380

381381
/// Allocate - Allocate memory from the ASTContext bump pointer.

include/swift/AST/Decl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3162,7 +3162,11 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
31623162
public:
31633163
using GenericTypeDecl::getASTContext;
31643164

3165-
ConstructorDecl *implicitConversionTo(Type type);
3165+
bool setConversionsComputed() {
3166+
bool wasComputed = implicitConversionsComputed;
3167+
implicitConversionsComputed = true;
3168+
return wasComputed;
3169+
}
31663170

31673171
SourceRange getBraces() const { return Braces; }
31683172

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ IDENTIFIER(identifier)
262262
IDENTIFIER(_distributedActorRemoteInitialize)
263263
IDENTIFIER(_distributedActorDestroy)
264264
IDENTIFIER(__isRemoteActor)
265+
IDENTIFIER(implicit)
265266

266267
#undef IDENTIFIER
267268
#undef IDENTIFIER_

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4243,8 +4243,8 @@ class ConstraintSystem {
42434243
SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
42444244
ConstraintLocatorBuilder locator);
42454245

4246-
/// Is a conversion from a Mutable to Immutable pointer possible.
4247-
bool toImmutablePossible(Type lhs, Type rhs);
4246+
/// Is an implicit conversion available from fromType to toType.
4247+
bool implicitConversionAvailable(Type fromType, Type toType);
42484248

42494249
/// Subroutine of \c matchTypes(), which matches up two tuple types.
42504250
///

lib/Sema/CSApply.cpp

Lines changed: 9 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6633,7 +6633,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
66336633
if (toType->hasUnresolvedType())
66346634
break;
66356635

6636-
if (cs.toImmutablePossible(fromType->lookThroughAllOptionalTypes(),
6636+
if (cs.implicitConversionAvailable(fromType->lookThroughAllOptionalTypes(),
66376637
toType->lookThroughAllOptionalTypes()))
66386638
break;
66396639

@@ -6857,56 +6857,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
68576857
}
68586858

68596859
case ConversionRestrictionKind::CGFloatToDouble:
6860-
case ConversionRestrictionKind::DoubleToCGFloat: {
6861-
auto conversionKind = knownRestriction->second;
6862-
6863-
auto *argExpr = locator.trySimplifyToExpr();
6864-
assert(argExpr);
6865-
6866-
// Load the value for conversion.
6867-
argExpr = cs.coerceToRValue(argExpr);
6868-
6869-
auto *implicitInit =
6870-
CallExpr::createImplicit(ctx, TypeExpr::createImplicit(toType, ctx),
6871-
/*args=*/{argExpr},
6872-
/*argLabels=*/{Identifier()});
6873-
6874-
cs.cacheExprTypes(implicitInit->getFn());
6875-
cs.setType(argExpr, fromType);
6876-
cs.setType(implicitInit->getArg(),
6877-
ParenType::get(cs.getASTContext(), fromType));
6878-
6879-
auto *callLocator = cs.getConstraintLocator(
6880-
implicitInit, LocatorPathElt::ImplicitConversion(conversionKind));
6881-
6882-
// HACK: Temporarily push the call expr onto the expr stack to make sure
6883-
// we don't try to prematurely close an existential when applying the
6884-
// curried member ref. This can be removed once existential opening is
6885-
// refactored not to rely on the shape of the AST prior to rewriting.
6886-
ExprStack.push_back(implicitInit);
6887-
SWIFT_DEFER { ExprStack.pop_back(); };
6888-
6889-
// We need to take information recorded for all conversions of this
6890-
// kind and move it to a specific location where restriction is applied.
6891-
{
6892-
auto *memberLoc = solution.getConstraintLocator(
6893-
callLocator, {ConstraintLocator::ApplyFunction,
6894-
ConstraintLocator::ConstructorMember});
6895-
6896-
auto overload = solution.getOverloadChoice(cs.getConstraintLocator(
6897-
ASTNode(), {LocatorPathElt::ImplicitConversion(conversionKind),
6898-
ConstraintLocator::ApplyFunction,
6899-
ConstraintLocator::ConstructorMember}));
6900-
6901-
solution.overloadChoices.insert({memberLoc, overload});
6902-
}
6903-
6904-
// Record the implicit call's parameter bindings and match direction.
6905-
solution.recordSingleArgMatchingChoice(callLocator);
6906-
6907-
finishApply(implicitInit, toType, callLocator, callLocator);
6908-
return implicitInit;
6909-
}
6860+
case ConversionRestrictionKind::DoubleToCGFloat:
69106861
case ConversionRestrictionKind::ImplicitConversion: {
69116862
auto conversionKind = knownRestriction->second;
69126863

@@ -6916,10 +6867,15 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
69166867
// Load the value for conversion.
69176868
argExpr = cs.coerceToRValue(argExpr);
69186869

6870+
Identifier label;
6871+
if (knownRestriction->second ==
6872+
ConversionRestrictionKind::ImplicitConversion)
6873+
label = cs.getASTContext().Id_implicit;
6874+
69196875
auto *implicitInit =
69206876
CallExpr::createImplicit(ctx, TypeExpr::createImplicit(toType, ctx),
69216877
/*args=*/{argExpr},
6922-
/*argLabels=*/{ctx.Id_implicit});
6878+
/*argLabels=*/{label});
69236879

69246880
cs.cacheExprTypes(implicitInit->getFn());
69256881
cs.setType(argExpr, fromType);
@@ -6938,7 +6894,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
69386894

69396895
// We need to take information recorded for all conversions of this
69406896
// kind and move it to a specific location where restriction is applied.
6941-
if (01) {
6897+
{
69426898
auto *memberLoc = solution.getConstraintLocator(
69436899
callLocator, {ConstraintLocator::ApplyFunction,
69446900
ConstraintLocator::ConstructorMember});

lib/Sema/CSSimplify.cpp

Lines changed: 66 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3635,6 +3635,10 @@ static bool repairOutOfOrderArgumentsInBinaryFunction(
36353635
return false;
36363636
}
36373637

3638+
/// Switch between restrictions mechanism and original PR using
3639+
/// ConversionRestrictionKind::PointerToPointer in repairFailures().
3640+
static bool useRestrictions = true;
3641+
36383642
/// Attempt to repair typing failures and record fixes if needed.
36393643
/// \return true if at least some of the failures has been repaired
36403644
/// successfully, which allows type matcher to continue.
@@ -4972,21 +4976,56 @@ bool ConstraintSystem::repairFailures(
49724976
}
49734977

49744978
// Accept mutable pointers in the place of immutables.
4975-
if (toImmutablePossible(lhs, rhs))
4979+
if (implicitConversionAvailable(lhs, rhs))
49764980
conversionsOrFixes.push_back(
49774981
ConversionRestrictionKind::PointerToPointer);
49784982

49794983
return !conversionsOrFixes.empty();
49804984
}
49814985

4982-
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
4988-
if (rhs->isUnsafeRawPointer() && (lhs->isUnsafeMutableRawPointer() ||
4989-
lhs->isUnsafeMutablePointer() || lhs->isUnsafePointer())) {
4986+
bool ConstraintSystem::implicitConversionAvailable(Type fromType, Type toType) {
4987+
#if 01 // Determine implicit conversions from init(implicit:) constructors
4988+
fprintf(stderr, "\n\nFROM %p ", fromType.getPointer());
4989+
fromType->dump();
4990+
fprintf(stderr, "TO %p ", toType.getPointer());
4991+
toType->dump();
4992+
if (NominalTypeDecl *toNominal = toType->getAnyNominal()) {
4993+
auto typeKey = ^TypeBase *(Type t) {
4994+
return t->getAnyNominal()->getInterfaceType()
4995+
->getCanonicalType().getPointer();
4996+
};
4997+
TypeBase *toBase = typeKey(toType);
4998+
auto &ctx = getASTContext();
4999+
if (!toNominal->setConversionsComputed()) {
5000+
auto implicitArgId = ctx.Id_implicit;
5001+
for (ExtensionDecl *extension : toNominal->getExtensions()) {
5002+
Type extType = extension->getDeclaredInterfaceType()->getCanonicalType();
5003+
fprintf(stderr, "\nEXT %p ", extType.getPointer());
5004+
extType->dump();
5005+
for (Decl *member : extension->getMembers())
5006+
if (ConstructorDecl *initDecl = dyn_cast<ConstructorDecl>(member)) {
5007+
ParameterList *args = initDecl->getParameters();
5008+
if (args->size() == 1 &&
5009+
args->get(0)->getBaseName().getIdentifier() == implicitArgId) {
5010+
Type argType = args->get(0)->getType()->getCanonicalType();
5011+
fprintf(stderr, "ARG %p ", argType.getPointer());
5012+
argType->dump();
5013+
(*ctx.implicitConversionsTo(typeKey(extType), /*create*/true))
5014+
[typeKey(argType)].push_back(initDecl);
5015+
}
5016+
}
5017+
}
5018+
}
5019+
if (auto *exists = ctx.implicitConversionsTo(toBase, /*create*/false)) {
5020+
for (ConstructorDecl *initFunc : (*exists)[typeKey(fromType)])
5021+
// More detailed check of conversion here...
5022+
if (initFunc != nullptr)
5023+
return true;
5024+
}
5025+
}
5026+
#else // Original hard coded rules.
5027+
if (toType->isUnsafeRawPointer() && (fromType->isUnsafeMutableRawPointer() ||
5028+
fromType->isUnsafeMutablePointer() || fromType->isUnsafePointer())) {
49905029
return true; // Unsafe[Mutable][Raw]Pointer -> UnsafeRawPointer
49915030
}
49925031
@@ -4995,39 +5034,16 @@ bool ConstraintSystem::toImmutablePossible(Type lhs, Type rhs) {
49955034
->getGenericArgs()[0]->getCanonicalType();
49965035
};
49975036
4998-
if (lhs->isUnsafeMutablePointer() && rhs->isUnsafePointer() &&
4999-
firstGenericArgument(lhs) == firstGenericArgument(rhs)) {
5000-
rhs->dump();
5001-
lhs->dump();
5037+
if (fromType->isUnsafeMutablePointer() && toType->isUnsafePointer() &&
5038+
firstGenericArgument(fromType) == firstGenericArgument(toType)) {
5039+
toType->dump();
5040+
fromType->dump();
50025041
return true; // UnsafeMutablePointer<Pointee> -> UnsafePointer<Pointee>
50035042
}
50045043
#endif
50055044
return false;
50065045
}
50075046

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-
50315047
ConstraintSystem::TypeMatchResult
50325048
ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
50335049
TypeMatchOptions flags,
@@ -5374,7 +5390,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
53745390
if (kind >= ConstraintKind::Subtype &&
53755391
nominal1->getDecl() != nominal2->getDecl() &&
53765392
((nominal1->isCGFloatType() || nominal2->isCGFloatType()) &&
5377-
(nominal1->isDouble() || nominal2->isDouble()))) {
5393+
(nominal1->isDouble() || nominal2->isDouble())) ||
5394+
useRestrictions && implicitConversionAvailable(type1, type2)) {
53785395
ConstraintLocatorBuilder location{locator};
53795396
// Look through all value-to-optional promotions to allow
53805397
// conversions like Double -> CGFloat?? and vice versa.
@@ -5442,14 +5459,17 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
54425459
rawElt.getAs<LocatorPathElt::ImplicitConversion>()) {
54435460
auto convKind = elt->getConversionKind();
54445461
return convKind == ConversionRestrictionKind::DoubleToCGFloat ||
5445-
convKind == ConversionRestrictionKind::CGFloatToDouble;
5462+
convKind == ConversionRestrictionKind::CGFloatToDouble ||
5463+
convKind == ConversionRestrictionKind::ImplicitConversion;
54465464
}
54475465
return false;
54485466
})) {
54495467
conversionsOrFixes.push_back(
54505468
desugar1->isCGFloatType()
5451-
? ConversionRestrictionKind::CGFloatToDouble
5452-
: ConversionRestrictionKind::DoubleToCGFloat);
5469+
? ConversionRestrictionKind::CGFloatToDouble :
5470+
desugar2->isCGFloatType()
5471+
? ConversionRestrictionKind::DoubleToCGFloat :
5472+
ConversionRestrictionKind::ImplicitConversion);
54535473
}
54545474
}
54555475

@@ -11177,7 +11197,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1117711197
}
1117811198

1117911199
case ConversionRestrictionKind::DoubleToCGFloat:
11180-
case ConversionRestrictionKind::CGFloatToDouble: {
11200+
case ConversionRestrictionKind::CGFloatToDouble:
11201+
case ConversionRestrictionKind::ImplicitConversion: {
1118111202
// Prefer CGFloat -> Double over other way araund.
1118211203
auto impact =
1118311204
restriction == ConversionRestrictionKind::CGFloatToDouble ? 1 : 10;
@@ -11224,16 +11245,17 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1122411245
memberTy, DC, FunctionRefKind::DoubleApply,
1122511246
/*outerAlternatives=*/{}, memberLoc);
1122611247

11248+
Identifier label;
11249+
if (restriction == ConversionRestrictionKind::ImplicitConversion)
11250+
label = getASTContext().Id_implicit;
1122711251
addConstraint(ConstraintKind::ApplicableFunction,
11228-
FunctionType::get({FunctionType::Param(type1)}, type2),
11252+
FunctionType::get({FunctionType::Param(type1, label)}, type2),
1122911253
memberTy, applicationLoc);
1123011254

1123111255
ImplicitValueConversions.push_back(
1123211256
{getConstraintLocator(locator), restriction});
1123311257
return SolutionKind::Solved;
1123411258
}
11235-
case ConversionRestrictionKind::ImplicitConversion:
11236-
return SolutionKind::Solved;
1123711259
}
1123811260

1123911261
llvm_unreachable("bad conversion restriction");

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,8 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator(
452452
if (auto conversion =
453453
locator->findLast<LocatorPathElt::ImplicitConversion>()) {
454454
if (conversion->is(ConversionRestrictionKind::DoubleToCGFloat) ||
455-
conversion->is(ConversionRestrictionKind::CGFloatToDouble)) {
455+
conversion->is(ConversionRestrictionKind::CGFloatToDouble) ||
456+
conversion->is(ConversionRestrictionKind::ImplicitConversion)) {
456457
return getConstraintLocator(
457458
ASTNode(), {*conversion, ConstraintLocator::ApplyFunction,
458459
ConstraintLocator::ConstructorMember});

test/TypeCoercion/immutable_mutable.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extension UnsafePointer {
2222
let optionalMutableRawPointer = UnsafeMutableRawPointer(bitPattern: -3)
2323
let mutableRawPointer = optionalMutableRawPointer!
2424
let immutable: UnsafeRawPointer = mutableRawPointer
25-
let immutable2: UnsafeRawPointer? = optionalMutableRawPointer
25+
//let immutable2: UnsafeRawPointer? = optionalMutableRawPointer
2626
let optionalImmutable: UnsafeRawPointer? = mutableRawPointer
2727
let mutable: UnsafeMutableRawPointer = immutable // expected-error {{cannot convert value of type 'UnsafeRawPointer' to specified type 'UnsafeMutableRawPointer'}}
2828

@@ -34,7 +34,7 @@ func unmutable(immutable: UnsafeRawPointer) -> UnsafeRawPointer {
3434
return mutableRawPointer
3535
}
3636
func unmutable(optionalImmutable: UnsafeRawPointer?) -> UnsafeRawPointer? {
37-
return optionalMutableRawPointer
37+
return optionalImmutable//optionalMutableRawPointer
3838
}
3939

4040
_ = unmutable(immutable: mutableRawPointer)
@@ -56,7 +56,7 @@ func demutable(immutable: UnsafePointer<Int>) -> UnsafeRawPointer {
5656
return mutableRawPointer
5757
}
5858
func demutable(optionalImmutable: UnsafePointer<Int>?) -> UnsafeRawPointer? {
59-
return optionalMutableRawPointer
59+
return optionalImmutable//optionalMutableRawPointer
6060
}
6161

6262
_ = demutable(immutable: mutable3)

0 commit comments

Comments
 (0)