Skip to content

Commit 5d59600

Browse files
authored
Merge pull request #25350 from slavapestov/object-literal-expr
Convert ObjectLiteralExpr to not use tc.callWitness() or generate a SemanticExpr
2 parents bbd44a1 + ae5a427 commit 5d59600

26 files changed

+255
-152
lines changed

include/swift/AST/Expr.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,7 @@ class ObjectLiteralExpr final
11351135
Expr *Arg;
11361136
Expr *SemanticExpr;
11371137
SourceLoc PoundLoc;
1138+
ConcreteDeclRef Initializer;
11381139

11391140
ObjectLiteralExpr(SourceLoc PoundLoc, LiteralKind LitKind,
11401141
Expr *Arg,
@@ -1195,6 +1196,15 @@ class ObjectLiteralExpr final
11951196

11961197
StringRef getLiteralKindPlainName() const;
11971198

1199+
/// Retrieve the initializer that will be used to construct the 'object'
1200+
/// literal from the result of the initializer.
1201+
ConcreteDeclRef getInitializer() const { return Initializer; }
1202+
1203+
/// Set the initializer that will be used to construct the 'object' literal.
1204+
void setInitializer(ConcreteDeclRef initializer) {
1205+
Initializer = initializer;
1206+
}
1207+
11981208
static bool classof(const Expr *E) {
11991209
return E->getKind() == ExprKind::ObjectLiteral;
12001210
}

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,6 +1967,8 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
19671967
void visitObjectLiteralExpr(ObjectLiteralExpr *E) {
19681968
printCommon(E, "object_literal")
19691969
<< " kind='" << E->getLiteralKindPlainName() << "'";
1970+
PrintWithColorRAII(OS, LiteralValueColor) << " initializer=";
1971+
E->getInitializer().dump(PrintWithColorRAII(OS, LiteralValueColor).getOS());
19701972
printArgumentLabels(E->getArgumentLabels());
19711973
OS << "\n";
19721974
printRec(E->getArg());

lib/AST/ProtocolConformance.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -966,8 +966,23 @@ Witness SelfProtocolConformance::getWitness(ValueDecl *requirement,
966966
ConcreteDeclRef
967967
RootProtocolConformance::getWitnessDeclRef(ValueDecl *requirement,
968968
LazyResolver *resolver) const {
969-
if (auto witness = getWitness(requirement, resolver))
970-
return witness.getDeclRef();
969+
if (auto witness = getWitness(requirement, resolver)) {
970+
auto *witnessDecl = witness.getDecl();
971+
972+
// If the witness is generic, you have to call getWitness() and build
973+
// your own substitutions in terms of the synthetic environment.
974+
if (auto *witnessDC = dyn_cast<DeclContext>(witnessDecl))
975+
assert(!witnessDC->isInnermostContextGeneric());
976+
977+
// If the witness is not generic, use type substitutions from the
978+
// witness's parent. Don't use witness.getSubstitutions(), which
979+
// are written in terms of the synthetic environment.
980+
auto subs =
981+
getType()->getContextSubstitutionMap(getDeclContext()->getParentModule(),
982+
witnessDecl->getDeclContext());
983+
return ConcreteDeclRef(witness.getDecl(), subs);
984+
}
985+
971986
return ConcreteDeclRef();
972987
}
973988

@@ -1120,11 +1135,6 @@ SpecializedProtocolConformance::getWitnessDeclRef(
11201135
auto witnessMap = baseWitness.getSubstitutions();
11211136

11221137
auto combinedMap = witnessMap.subst(specializationMap);
1123-
1124-
// Fast path if the substitutions didn't change.
1125-
if (combinedMap == baseWitness.getSubstitutions())
1126-
return baseWitness;
1127-
11281138
return ConcreteDeclRef(witnessDecl, combinedMap);
11291139
}
11301140

lib/SILGen/SILGenExpr.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2346,7 +2346,14 @@ visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E,
23462346

23472347
RValue RValueEmitter::
23482348
visitObjectLiteralExpr(ObjectLiteralExpr *E, SGFContext C) {
2349-
return visit(E->getSemanticExpr(), C);
2349+
ConcreteDeclRef init = E->getInitializer();
2350+
auto *decl = cast<ConstructorDecl>(init.getDecl());
2351+
AnyFunctionType *fnTy = decl->getMethodInterfaceType()
2352+
.subst(init.getSubstitutions())
2353+
->getAs<AnyFunctionType>();
2354+
PreparedArguments args(fnTy->getParams(), E->getArg());
2355+
return SGF.emitApplyAllocatingInitializer(SILLocation(E), init,
2356+
std::move(args), E->getType(), C);
23502357
}
23512358

23522359
RValue RValueEmitter::

lib/Sema/CSApply.cpp

Lines changed: 32 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ SubstitutionMap Solution::computeSubstitutions(
7777
for (const auto &opened : openedTypes->second)
7878
subs[opened.first] = getFixedType(opened.second);
7979

80-
auto &tc = getConstraintSystem().getTypeChecker();
81-
8280
auto lookupConformanceFn =
8381
[&](CanType original, Type replacement, ProtocolDecl *protoType)
8482
-> Optional<ProtocolConformanceRef> {
@@ -88,9 +86,9 @@ SubstitutionMap Solution::computeSubstitutions(
8886
return ProtocolConformanceRef(protoType);
8987
}
9088

91-
return tc.conformsToProtocol(replacement, protoType,
92-
getConstraintSystem().DC,
93-
ConformanceCheckFlags::InExpression);
89+
return TypeChecker::conformsToProtocol(replacement, protoType,
90+
getConstraintSystem().DC,
91+
ConformanceCheckFlags::InExpression);
9492
};
9593

9694
return SubstitutionMap::get(sig,
@@ -425,7 +423,7 @@ namespace {
425423
if (!baseTy->is<ArchetypeType>() && !baseTy->isAnyExistentialType()) {
426424
auto &tc = cs.getTypeChecker();
427425
auto conformance =
428-
tc.conformsToProtocol(
426+
TypeChecker::conformsToProtocol(
429427
baseTy, proto, cs.DC,
430428
ConformanceCheckFlags::InExpression);
431429
if (conformance && conformance->isConcrete()) {
@@ -1694,10 +1692,10 @@ namespace {
16941692

16951693
// Try to find the conformance of the value type to _BridgedToObjectiveC.
16961694
auto bridgedToObjectiveCConformance
1697-
= tc.conformsToProtocol(valueType,
1698-
bridgedProto,
1699-
cs.DC,
1700-
ConformanceCheckFlags::InExpression);
1695+
= TypeChecker::conformsToProtocol(valueType,
1696+
bridgedProto,
1697+
cs.DC,
1698+
ConformanceCheckFlags::InExpression);
17011699

17021700
FuncDecl *fn = nullptr;
17031701

@@ -1973,8 +1971,8 @@ namespace {
19731971
ProtocolDecl *protocol = tc.getProtocol(
19741972
expr->getLoc(), KnownProtocolKind::ExpressibleByStringLiteral);
19751973

1976-
if (!tc.conformsToProtocol(type, protocol, cs.DC,
1977-
ConformanceCheckFlags::InExpression)) {
1974+
if (!TypeChecker::conformsToProtocol(type, protocol, cs.DC,
1975+
ConformanceCheckFlags::InExpression)) {
19781976
// If the type does not conform to ExpressibleByStringLiteral, it should
19791977
// be ExpressibleByExtendedGraphemeClusterLiteral.
19801978
protocol = tc.getProtocol(
@@ -1983,8 +1981,8 @@ namespace {
19831981
isStringLiteral = false;
19841982
isGraphemeClusterLiteral = true;
19851983
}
1986-
if (!tc.conformsToProtocol(type, protocol, cs.DC,
1987-
ConformanceCheckFlags::InExpression)) {
1984+
if (!TypeChecker::conformsToProtocol(type, protocol, cs.DC,
1985+
ConformanceCheckFlags::InExpression)) {
19881986
// ... or it should be ExpressibleByUnicodeScalarLiteral.
19891987
protocol = tc.getProtocol(
19901988
expr->getLoc(),
@@ -2105,8 +2103,8 @@ namespace {
21052103
assert(proto && "Missing string interpolation protocol?");
21062104

21072105
auto conformance =
2108-
tc.conformsToProtocol(type, proto, cs.DC,
2109-
ConformanceCheckFlags::InExpression);
2106+
TypeChecker::conformsToProtocol(type, proto, cs.DC,
2107+
ConformanceCheckFlags::InExpression);
21102108
assert(conformance && "string interpolation type conforms to protocol");
21112109

21122110
DeclName constrName(tc.Context, DeclBaseName::createConstructor(), argLabels);
@@ -2213,7 +2211,6 @@ namespace {
22132211
if (cs.getType(expr) && !cs.getType(expr)->hasTypeVariable())
22142212
return expr;
22152213

2216-
auto &ctx = cs.getASTContext();
22172214
auto &tc = cs.getTypeChecker();
22182215

22192216
// Figure out the type we're converting to.
@@ -2234,34 +2231,18 @@ namespace {
22342231
auto proto = tc.getLiteralProtocol(expr);
22352232
assert(proto && "Missing object literal protocol?");
22362233
auto conformance =
2237-
tc.conformsToProtocol(conformingType, proto, cs.DC,
2238-
ConformanceCheckFlags::InExpression);
2234+
TypeChecker::conformsToProtocol(conformingType, proto, cs.DC,
2235+
ConformanceCheckFlags::InExpression);
22392236
assert(conformance && "object literal type conforms to protocol");
22402237

2241-
Expr *base = TypeExpr::createImplicitHack(expr->getLoc(), conformingType,
2242-
ctx);
2243-
cs.cacheExprTypes(base);
2244-
2245-
SmallVector<Expr *, 4> args;
2246-
if (!isa<TupleExpr>(expr->getArg()))
2247-
return nullptr;
2248-
auto tupleArg = cast<TupleExpr>(expr->getArg());
2249-
for (auto elt : tupleArg->getElements()) {
2250-
cs.setExprTypes(elt);
2251-
args.push_back(elt);
2252-
}
22532238
DeclName constrName(tc.getObjectLiteralConstructorName(expr));
22542239

2255-
cs.cacheExprTypes(base);
2256-
cs.setExprTypes(base);
2257-
2258-
Expr *semanticExpr = tc.callWitness(base, dc, proto, *conformance,
2259-
constrName, args,
2260-
diag::object_literal_broken_proto);
2261-
if (semanticExpr)
2262-
cs.cacheExprTypes(semanticExpr);
2263-
2264-
expr->setSemanticExpr(semanticExpr);
2240+
ConcreteDeclRef witness =
2241+
conformance->getWitnessByName(conformingType->getRValueType(),
2242+
constrName);
2243+
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
2244+
return nullptr;
2245+
expr->setInitializer(witness);
22652246
return expr;
22662247
}
22672248

@@ -2898,8 +2879,8 @@ namespace {
28982879
assert(arrayProto && "type-checked array literal w/o protocol?!");
28992880

29002881
auto conformance =
2901-
tc.conformsToProtocol(arrayTy, arrayProto, cs.DC,
2902-
ConformanceCheckFlags::InExpression);
2882+
TypeChecker::conformsToProtocol(arrayTy, arrayProto, cs.DC,
2883+
ConformanceCheckFlags::InExpression);
29032884
assert(conformance && "Type does not conform to protocol?");
29042885

29052886
DeclName name(tc.Context, DeclBaseName::createConstructor(),
@@ -2943,8 +2924,8 @@ namespace {
29432924
KnownProtocolKind::ExpressibleByDictionaryLiteral);
29442925

29452926
auto conformance =
2946-
tc.conformsToProtocol(dictionaryTy, dictionaryProto, cs.DC,
2947-
ConformanceCheckFlags::InExpression);
2927+
TypeChecker::conformsToProtocol(dictionaryTy, dictionaryProto, cs.DC,
2928+
ConformanceCheckFlags::InExpression);
29482929
if (!conformance)
29492930
return nullptr;
29502931

@@ -4572,16 +4553,15 @@ namespace {
45724553
auto hashable =
45734554
cs.getASTContext().getProtocol(KnownProtocolKind::Hashable);
45744555

4575-
auto &TC = cs.getTypeChecker();
45764556
auto fnType = overload.openedType->castTo<FunctionType>();
45774557
for (const auto &param : fnType->getParams()) {
45784558
auto indexType = simplifyType(param.getPlainType());
45794559
// Index type conformance to Hashable protocol has been
45804560
// verified by the solver, we just need to get it again
45814561
// with all of the generic parameters resolved.
45824562
auto hashableConformance =
4583-
TC.conformsToProtocol(indexType, hashable, cs.DC,
4584-
ConformanceCheckFlags::InExpression);
4563+
TypeChecker::conformsToProtocol(indexType, hashable, cs.DC,
4564+
ConformanceCheckFlags::InExpression);
45854565
assert(hashableConformance.hasValue());
45864566

45874567
conformances.push_back(*hashableConformance);
@@ -6242,7 +6222,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
62426222
// Find the conformance of the source type to Hashable.
62436223
auto hashable = tc.Context.getProtocol(KnownProtocolKind::Hashable);
62446224
auto conformance =
6245-
tc.conformsToProtocol(
6225+
TypeChecker::conformsToProtocol(
62466226
cs.getType(expr), hashable, cs.DC,
62476227
ConformanceCheckFlags::InExpression);
62486228
assert(conformance && "must conform to Hashable");
@@ -6748,8 +6728,8 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
67486728
Optional<ProtocolConformanceRef> builtinConformance;
67496729
if (builtinProtocol &&
67506730
(builtinConformance =
6751-
tc.conformsToProtocol(type, builtinProtocol, cs.DC,
6752-
ConformanceCheckFlags::InExpression))) {
6731+
TypeChecker::conformsToProtocol(type, builtinProtocol, cs.DC,
6732+
ConformanceCheckFlags::InExpression))) {
67536733

67546734
// Find the witness that we'll use to initialize the type via a builtin
67556735
// literal.
@@ -6780,7 +6760,7 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
67806760

67816761
// This literal type must conform to the (non-builtin) protocol.
67826762
assert(protocol && "requirements should have stopped recursion");
6783-
auto conformance = tc.conformsToProtocol(type, protocol, cs.DC,
6763+
auto conformance = TypeChecker::conformsToProtocol(type, protocol, cs.DC,
67846764
ConformanceCheckFlags::InExpression);
67856765
assert(conformance && "must conform to literal protocol");
67866766

lib/Sema/CSBindings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
676676

677677
do {
678678
// If the type conforms to this protocol, we're covered.
679-
if (tc.conformsToProtocol(
679+
if (TypeChecker::conformsToProtocol(
680680
testType, protocol, DC,
681681
(ConformanceCheckFlags::InExpression |
682682
ConformanceCheckFlags::SkipConditionalRequirements))) {

lib/Sema/CSDiag.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,7 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
12121212
}
12131213

12141214
// Emit a conformance error through conformsToProtocol.
1215-
if (auto conformance = CS.TC.conformsToProtocol(
1215+
if (auto conformance = TypeChecker::conformsToProtocol(
12161216
fromType, PT->getDecl(), CS.DC, ConformanceCheckFlags::InExpression,
12171217
expr->getLoc())) {
12181218
if (conformance->isAbstract() ||
@@ -1724,8 +1724,8 @@ static bool conformsToKnownProtocol(Type fromType, KnownProtocolKind kind,
17241724
if (!proto)
17251725
return false;
17261726

1727-
if (CS.TC.conformsToProtocol(fromType, proto, CS.DC,
1728-
ConformanceCheckFlags::InExpression)) {
1727+
if (TypeChecker::conformsToProtocol(fromType, proto, CS.DC,
1728+
ConformanceCheckFlags::InExpression)) {
17291729
return true;
17301730
}
17311731

@@ -1745,7 +1745,7 @@ static Type isRawRepresentable(Type fromType, const ConstraintSystem &CS) {
17451745
if (!rawReprType)
17461746
return Type();
17471747

1748-
auto conformance = CS.TC.conformsToProtocol(
1748+
auto conformance = TypeChecker::conformsToProtocol(
17491749
fromType, rawReprType, CS.DC, ConformanceCheckFlags::InExpression);
17501750
if (!conformance)
17511751
return Type();
@@ -2122,8 +2122,8 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
21222122
if (auto errorCodeProtocol =
21232123
TC.Context.getProtocol(KnownProtocolKind::ErrorCodeProtocol)) {
21242124
if (auto conformance =
2125-
TC.conformsToProtocol(CS.getType(expr), errorCodeProtocol, CS.DC,
2126-
ConformanceCheckFlags::InExpression)) {
2125+
TypeChecker::conformsToProtocol(CS.getType(expr), errorCodeProtocol, CS.DC,
2126+
ConformanceCheckFlags::InExpression)) {
21272127
Type errorCodeType = CS.getType(expr);
21282128
Type errorType =
21292129
conformance->getTypeWitnessByName(errorCodeType,
@@ -6261,8 +6261,8 @@ bool FailureDiagnosis::visitArrayExpr(ArrayExpr *E) {
62616261

62626262
// Check to see if the contextual type conforms.
62636263
if (auto Conformance
6264-
= CS.TC.conformsToProtocol(contextualType, ALC, CS.DC,
6265-
ConformanceCheckFlags::InExpression)) {
6264+
= TypeChecker::conformsToProtocol(contextualType, ALC, CS.DC,
6265+
ConformanceCheckFlags::InExpression)) {
62666266
Type contextualElementType =
62676267
Conformance->getTypeWitnessByName(
62686268
contextualType, CS.getASTContext().Id_ArrayLiteralElement)
@@ -6286,8 +6286,8 @@ bool FailureDiagnosis::visitArrayExpr(ArrayExpr *E) {
62866286
if (!DLC)
62876287
return visitExpr(E);
62886288

6289-
if (CS.TC.conformsToProtocol(contextualType, DLC, CS.DC,
6290-
ConformanceCheckFlags::InExpression)) {
6289+
if (TypeChecker::conformsToProtocol(contextualType, DLC, CS.DC,
6290+
ConformanceCheckFlags::InExpression)) {
62916291
// If the contextual type conforms to ExpressibleByDictionaryLiteral and
62926292
// this is an empty array, then they meant "[:]".
62936293
auto numElements = E->getNumElements();
@@ -6344,7 +6344,7 @@ bool FailureDiagnosis::visitDictionaryExpr(DictionaryExpr *E) {
63446344

63456345
// Validate the contextual type conforms to ExpressibleByDictionaryLiteral
63466346
// and figure out what the contextual Key/Value types are in place.
6347-
auto Conformance = CS.TC.conformsToProtocol(
6347+
auto Conformance = TypeChecker::conformsToProtocol(
63486348
contextualType, DLC, CS.DC, ConformanceCheckFlags::InExpression);
63496349
if (!Conformance) {
63506350
diagnose(E->getStartLoc(), diag::type_is_not_dictionary, contextualType)

lib/Sema/CSGen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,8 +577,8 @@ namespace {
577577
// the literal.
578578
if (otherArgTy && otherArgTy->getAnyNominal()) {
579579
if (otherArgTy->isEqual(paramTy) &&
580-
tc.conformsToProtocol(otherArgTy, literalProto, CS.DC,
581-
ConformanceCheckFlags::InExpression))
580+
TypeChecker::conformsToProtocol(otherArgTy, literalProto, CS.DC,
581+
ConformanceCheckFlags::InExpression))
582582
return true;
583583
} else if (Type defaultType = tc.getDefaultType(literalProto, CS.DC)) {
584584
// If there is a default type for the literal protocol, check whether

lib/Sema/CSRanking.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ computeSelfTypeRelationship(TypeChecker &tc, DeclContext *dc, ValueDecl *decl1,
249249

250250
// If the model type does not conform to the protocol, the bases are
251251
// unrelated.
252-
auto conformance = tc.conformsToProtocol(
252+
auto conformance = TypeChecker::conformsToProtocol(
253253
modelTy, proto, dc,
254254
(ConformanceCheckFlags::InExpression|
255255
ConformanceCheckFlags::SkipConditionalRequirements));

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3329,7 +3329,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
33293329
case ConstraintKind::LiteralConformsTo: {
33303330
// Check whether this type conforms to the protocol.
33313331
if (auto conformance =
3332-
TC.conformsToProtocol(
3332+
TypeChecker::conformsToProtocol(
33333333
type, protocol, DC,
33343334
(ConformanceCheckFlags::InExpression|
33353335
ConformanceCheckFlags::SkipConditionalRequirements))) {

0 commit comments

Comments
 (0)