Skip to content
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
10 changes: 10 additions & 0 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,7 @@ class ObjectLiteralExpr final
Expr *Arg;
Expr *SemanticExpr;
SourceLoc PoundLoc;
ConcreteDeclRef Initializer;

ObjectLiteralExpr(SourceLoc PoundLoc, LiteralKind LitKind,
Expr *Arg,
Expand Down Expand Up @@ -1195,6 +1196,15 @@ class ObjectLiteralExpr final

StringRef getLiteralKindPlainName() const;

/// Retrieve the initializer that will be used to construct the 'object'
/// literal from the result of the initializer.
ConcreteDeclRef getInitializer() const { return Initializer; }

/// Set the initializer that will be used to construct the 'object' literal.
void setInitializer(ConcreteDeclRef initializer) {
Initializer = initializer;
}

static bool classof(const Expr *E) {
return E->getKind() == ExprKind::ObjectLiteral;
}
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1967,6 +1967,8 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
void visitObjectLiteralExpr(ObjectLiteralExpr *E) {
printCommon(E, "object_literal")
<< " kind='" << E->getLiteralKindPlainName() << "'";
PrintWithColorRAII(OS, LiteralValueColor) << " initializer=";
E->getInitializer().dump(PrintWithColorRAII(OS, LiteralValueColor).getOS());
printArgumentLabels(E->getArgumentLabels());
OS << "\n";
printRec(E->getArg());
Expand Down
24 changes: 17 additions & 7 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -966,8 +966,23 @@ Witness SelfProtocolConformance::getWitness(ValueDecl *requirement,
ConcreteDeclRef
RootProtocolConformance::getWitnessDeclRef(ValueDecl *requirement,
LazyResolver *resolver) const {
if (auto witness = getWitness(requirement, resolver))
return witness.getDeclRef();
if (auto witness = getWitness(requirement, resolver)) {
auto *witnessDecl = witness.getDecl();

// If the witness is generic, you have to call getWitness() and build
// your own substitutions in terms of the synthetic environment.
if (auto *witnessDC = dyn_cast<DeclContext>(witnessDecl))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be triggered by just another level of genericness in the crasher example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ll take a look. It would not have worked before anyway though.

assert(!witnessDC->isInnermostContextGeneric());

// If the witness is not generic, use type substitutions from the
// witness's parent. Don't use witness.getSubstitutions(), which
// are written in terms of the synthetic environment.
auto subs =
getType()->getContextSubstitutionMap(getDeclContext()->getParentModule(),
witnessDecl->getDeclContext());
return ConcreteDeclRef(witness.getDecl(), subs);
}

return ConcreteDeclRef();
}

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

auto combinedMap = witnessMap.subst(specializationMap);

// Fast path if the substitutions didn't change.
if (combinedMap == baseWitness.getSubstitutions())
return baseWitness;

return ConcreteDeclRef(witnessDecl, combinedMap);
}

Expand Down
9 changes: 8 additions & 1 deletion lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2346,7 +2346,14 @@ visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E,

RValue RValueEmitter::
visitObjectLiteralExpr(ObjectLiteralExpr *E, SGFContext C) {
return visit(E->getSemanticExpr(), C);
ConcreteDeclRef init = E->getInitializer();
auto *decl = cast<ConstructorDecl>(init.getDecl());
AnyFunctionType *fnTy = decl->getMethodInterfaceType()
.subst(init.getSubstitutions())
->getAs<AnyFunctionType>();
PreparedArguments args(fnTy->getParams(), E->getArg());
return SGF.emitApplyAllocatingInitializer(SILLocation(E), init,
std::move(args), E->getType(), C);
}

RValue RValueEmitter::
Expand Down
84 changes: 32 additions & 52 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ SubstitutionMap Solution::computeSubstitutions(
for (const auto &opened : openedTypes->second)
subs[opened.first] = getFixedType(opened.second);

auto &tc = getConstraintSystem().getTypeChecker();

auto lookupConformanceFn =
[&](CanType original, Type replacement, ProtocolDecl *protoType)
-> Optional<ProtocolConformanceRef> {
Expand All @@ -88,9 +86,9 @@ SubstitutionMap Solution::computeSubstitutions(
return ProtocolConformanceRef(protoType);
}

return tc.conformsToProtocol(replacement, protoType,
getConstraintSystem().DC,
ConformanceCheckFlags::InExpression);
return TypeChecker::conformsToProtocol(replacement, protoType,
getConstraintSystem().DC,
ConformanceCheckFlags::InExpression);
};

return SubstitutionMap::get(sig,
Expand Down Expand Up @@ -425,7 +423,7 @@ namespace {
if (!baseTy->is<ArchetypeType>() && !baseTy->isAnyExistentialType()) {
auto &tc = cs.getTypeChecker();
auto conformance =
tc.conformsToProtocol(
TypeChecker::conformsToProtocol(
baseTy, proto, cs.DC,
ConformanceCheckFlags::InExpression);
if (conformance && conformance->isConcrete()) {
Expand Down Expand Up @@ -1694,10 +1692,10 @@ namespace {

// Try to find the conformance of the value type to _BridgedToObjectiveC.
auto bridgedToObjectiveCConformance
= tc.conformsToProtocol(valueType,
bridgedProto,
cs.DC,
ConformanceCheckFlags::InExpression);
= TypeChecker::conformsToProtocol(valueType,
bridgedProto,
cs.DC,
ConformanceCheckFlags::InExpression);

FuncDecl *fn = nullptr;

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

if (!tc.conformsToProtocol(type, protocol, cs.DC,
ConformanceCheckFlags::InExpression)) {
if (!TypeChecker::conformsToProtocol(type, protocol, cs.DC,
ConformanceCheckFlags::InExpression)) {
// If the type does not conform to ExpressibleByStringLiteral, it should
// be ExpressibleByExtendedGraphemeClusterLiteral.
protocol = tc.getProtocol(
Expand All @@ -1983,8 +1981,8 @@ namespace {
isStringLiteral = false;
isGraphemeClusterLiteral = true;
}
if (!tc.conformsToProtocol(type, protocol, cs.DC,
ConformanceCheckFlags::InExpression)) {
if (!TypeChecker::conformsToProtocol(type, protocol, cs.DC,
ConformanceCheckFlags::InExpression)) {
// ... or it should be ExpressibleByUnicodeScalarLiteral.
protocol = tc.getProtocol(
expr->getLoc(),
Expand Down Expand Up @@ -2105,8 +2103,8 @@ namespace {
assert(proto && "Missing string interpolation protocol?");

auto conformance =
tc.conformsToProtocol(type, proto, cs.DC,
ConformanceCheckFlags::InExpression);
TypeChecker::conformsToProtocol(type, proto, cs.DC,
ConformanceCheckFlags::InExpression);
assert(conformance && "string interpolation type conforms to protocol");

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

auto &ctx = cs.getASTContext();
auto &tc = cs.getTypeChecker();

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

Expr *base = TypeExpr::createImplicitHack(expr->getLoc(), conformingType,
ctx);
cs.cacheExprTypes(base);

SmallVector<Expr *, 4> args;
if (!isa<TupleExpr>(expr->getArg()))
return nullptr;
auto tupleArg = cast<TupleExpr>(expr->getArg());
for (auto elt : tupleArg->getElements()) {
cs.setExprTypes(elt);
args.push_back(elt);
}
DeclName constrName(tc.getObjectLiteralConstructorName(expr));

cs.cacheExprTypes(base);
cs.setExprTypes(base);

Expr *semanticExpr = tc.callWitness(base, dc, proto, *conformance,
constrName, args,
diag::object_literal_broken_proto);
if (semanticExpr)
cs.cacheExprTypes(semanticExpr);

expr->setSemanticExpr(semanticExpr);
ConcreteDeclRef witness =
conformance->getWitnessByName(conformingType->getRValueType(),
constrName);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;
expr->setInitializer(witness);
return expr;
}

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

auto conformance =
tc.conformsToProtocol(arrayTy, arrayProto, cs.DC,
ConformanceCheckFlags::InExpression);
TypeChecker::conformsToProtocol(arrayTy, arrayProto, cs.DC,
ConformanceCheckFlags::InExpression);
assert(conformance && "Type does not conform to protocol?");

DeclName name(tc.Context, DeclBaseName::createConstructor(),
Expand Down Expand Up @@ -2943,8 +2924,8 @@ namespace {
KnownProtocolKind::ExpressibleByDictionaryLiteral);

auto conformance =
tc.conformsToProtocol(dictionaryTy, dictionaryProto, cs.DC,
ConformanceCheckFlags::InExpression);
TypeChecker::conformsToProtocol(dictionaryTy, dictionaryProto, cs.DC,
ConformanceCheckFlags::InExpression);
if (!conformance)
return nullptr;

Expand Down Expand Up @@ -4572,16 +4553,15 @@ namespace {
auto hashable =
cs.getASTContext().getProtocol(KnownProtocolKind::Hashable);

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

conformances.push_back(*hashableConformance);
Expand Down Expand Up @@ -6242,7 +6222,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
// Find the conformance of the source type to Hashable.
auto hashable = tc.Context.getProtocol(KnownProtocolKind::Hashable);
auto conformance =
tc.conformsToProtocol(
TypeChecker::conformsToProtocol(
cs.getType(expr), hashable, cs.DC,
ConformanceCheckFlags::InExpression);
assert(conformance && "must conform to Hashable");
Expand Down Expand Up @@ -6748,8 +6728,8 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
Optional<ProtocolConformanceRef> builtinConformance;
if (builtinProtocol &&
(builtinConformance =
tc.conformsToProtocol(type, builtinProtocol, cs.DC,
ConformanceCheckFlags::InExpression))) {
TypeChecker::conformsToProtocol(type, builtinProtocol, cs.DC,
ConformanceCheckFlags::InExpression))) {

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

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

Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {

do {
// If the type conforms to this protocol, we're covered.
if (tc.conformsToProtocol(
if (TypeChecker::conformsToProtocol(
testType, protocol, DC,
(ConformanceCheckFlags::InExpression |
ConformanceCheckFlags::SkipConditionalRequirements))) {
Expand Down
22 changes: 11 additions & 11 deletions lib/Sema/CSDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,7 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
}

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

if (CS.TC.conformsToProtocol(fromType, proto, CS.DC,
ConformanceCheckFlags::InExpression)) {
if (TypeChecker::conformsToProtocol(fromType, proto, CS.DC,
ConformanceCheckFlags::InExpression)) {
return true;
}

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

auto conformance = CS.TC.conformsToProtocol(
auto conformance = TypeChecker::conformsToProtocol(
fromType, rawReprType, CS.DC, ConformanceCheckFlags::InExpression);
if (!conformance)
return Type();
Expand Down Expand Up @@ -2122,8 +2122,8 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
if (auto errorCodeProtocol =
TC.Context.getProtocol(KnownProtocolKind::ErrorCodeProtocol)) {
if (auto conformance =
TC.conformsToProtocol(CS.getType(expr), errorCodeProtocol, CS.DC,
ConformanceCheckFlags::InExpression)) {
TypeChecker::conformsToProtocol(CS.getType(expr), errorCodeProtocol, CS.DC,
ConformanceCheckFlags::InExpression)) {
Type errorCodeType = CS.getType(expr);
Type errorType =
conformance->getTypeWitnessByName(errorCodeType,
Expand Down Expand Up @@ -6261,8 +6261,8 @@ bool FailureDiagnosis::visitArrayExpr(ArrayExpr *E) {

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

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

// Validate the contextual type conforms to ExpressibleByDictionaryLiteral
// and figure out what the contextual Key/Value types are in place.
auto Conformance = CS.TC.conformsToProtocol(
auto Conformance = TypeChecker::conformsToProtocol(
contextualType, DLC, CS.DC, ConformanceCheckFlags::InExpression);
if (!Conformance) {
diagnose(E->getStartLoc(), diag::type_is_not_dictionary, contextualType)
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,8 @@ namespace {
// the literal.
if (otherArgTy && otherArgTy->getAnyNominal()) {
if (otherArgTy->isEqual(paramTy) &&
tc.conformsToProtocol(otherArgTy, literalProto, CS.DC,
ConformanceCheckFlags::InExpression))
TypeChecker::conformsToProtocol(otherArgTy, literalProto, CS.DC,
ConformanceCheckFlags::InExpression))
return true;
} else if (Type defaultType = tc.getDefaultType(literalProto, CS.DC)) {
// If there is a default type for the literal protocol, check whether
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSRanking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ computeSelfTypeRelationship(TypeChecker &tc, DeclContext *dc, ValueDecl *decl1,

// If the model type does not conform to the protocol, the bases are
// unrelated.
auto conformance = tc.conformsToProtocol(
auto conformance = TypeChecker::conformsToProtocol(
modelTy, proto, dc,
(ConformanceCheckFlags::InExpression|
ConformanceCheckFlags::SkipConditionalRequirements));
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3329,7 +3329,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
case ConstraintKind::LiteralConformsTo: {
// Check whether this type conforms to the protocol.
if (auto conformance =
TC.conformsToProtocol(
TypeChecker::conformsToProtocol(
type, protocol, DC,
(ConformanceCheckFlags::InExpression|
ConformanceCheckFlags::SkipConditionalRequirements))) {
Expand Down
Loading