From c84aad8bf195a641e504760dc909265191dc99fc Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 11 Jun 2019 01:29:54 -0700 Subject: [PATCH 1/4] Sema: TypeChecker::conformsToProtocol() is static --- lib/Sema/CSApply.cpp | 55 +++++++++---------- lib/Sema/CSBindings.cpp | 2 +- lib/Sema/CSDiag.cpp | 22 ++++---- lib/Sema/CSGen.cpp | 4 +- lib/Sema/CSRanking.cpp | 2 +- lib/Sema/CSSimplify.cpp | 2 +- lib/Sema/CSSolver.cpp | 12 ++-- lib/Sema/CalleeCandidateInfo.cpp | 4 +- lib/Sema/DerivedConformanceCodable.cpp | 42 +++++++------- .../DerivedConformanceEquatableHashable.cpp | 15 ++--- .../DerivedConformanceRawRepresentable.cpp | 6 +- lib/Sema/DerivedConformances.cpp | 2 +- lib/Sema/TypeCheckAttr.cpp | 21 +++---- lib/Sema/TypeCheckAvailability.cpp | 8 +-- lib/Sema/TypeCheckConstraints.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 13 +++-- lib/Sema/TypeCheckNameLookup.cpp | 8 +-- lib/Sema/TypeCheckProtocol.cpp | 7 ++- lib/Sema/TypeCheckProtocolInference.cpp | 2 +- lib/Sema/TypeCheckStmt.cpp | 12 ++-- 20 files changed, 120 insertions(+), 121 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 6e9da3712d9d8..912e24b11d170 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -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 { @@ -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, @@ -425,7 +423,7 @@ namespace { if (!baseTy->is() && !baseTy->isAnyExistentialType()) { auto &tc = cs.getTypeChecker(); auto conformance = - tc.conformsToProtocol( + TypeChecker::conformsToProtocol( baseTy, proto, cs.DC, ConformanceCheckFlags::InExpression); if (conformance && conformance->isConcrete()) { @@ -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; @@ -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( @@ -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(), @@ -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); @@ -2234,8 +2232,8 @@ 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, @@ -2898,8 +2896,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(), @@ -2943,8 +2941,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; @@ -4572,7 +4570,6 @@ namespace { auto hashable = cs.getASTContext().getProtocol(KnownProtocolKind::Hashable); - auto &TC = cs.getTypeChecker(); auto fnType = overload.openedType->castTo(); for (const auto ¶m : fnType->getParams()) { auto indexType = simplifyType(param.getPlainType()); @@ -4580,8 +4577,8 @@ namespace { // 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); @@ -6242,7 +6239,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"); @@ -6748,8 +6745,8 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal, Optional 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. @@ -6780,7 +6777,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"); diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 6258a705a552f..be679cebf0458 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -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))) { diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 55648f3829a91..ebe79ebcf8a0e 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -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() || @@ -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; } @@ -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(); @@ -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, @@ -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) @@ -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(); @@ -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) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 1403197f0237b..32b15bfa4afab 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -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 diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index d0e57049170d3..9ebd37f0ba150 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -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)); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index ee62373280539..c1d18a3a30c9b 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -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))) { diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index e0553b48401b8..9ff2b5f94edfd 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -1671,11 +1671,11 @@ void ConstraintSystem::ArgumentInfoCollector::minimizeLiteralProtocols() { const auto &candidate = candidates[i]; auto first = - CS.TC.conformsToProtocol(candidate.second, candidates[result].first, - CS.DC, ConformanceCheckFlags::InExpression); + TypeChecker::conformsToProtocol(candidate.second, candidates[result].first, + CS.DC, ConformanceCheckFlags::InExpression); auto second = - CS.TC.conformsToProtocol(candidates[result].second, candidate.first, - CS.DC, ConformanceCheckFlags::InExpression); + TypeChecker::conformsToProtocol(candidates[result].second, candidate.first, + CS.DC, ConformanceCheckFlags::InExpression); if ((first && second) || (!first && !second)) return; @@ -1878,8 +1878,8 @@ void ConstraintSystem::sortDesignatedTypes( ++nextType; break; } else if (auto *protoDecl = dyn_cast(nominalTypes[i])) { - if (TC.conformsToProtocol(argType, protoDecl, DC, - ConformanceCheckFlags::InExpression)) { + if (TypeChecker::conformsToProtocol(argType, protoDecl, DC, + ConformanceCheckFlags::InExpression)) { std::swap(nominalTypes[nextType], nominalTypes[i]); ++nextType; break; diff --git a/lib/Sema/CalleeCandidateInfo.cpp b/lib/Sema/CalleeCandidateInfo.cpp index 6628314c00b96..b74beb9366fab 100644 --- a/lib/Sema/CalleeCandidateInfo.cpp +++ b/lib/Sema/CalleeCandidateInfo.cpp @@ -1059,8 +1059,8 @@ bool CalleeCandidateInfo::diagnoseGenericParameterErrors(Expr *badArgExpr) { // FIXME: Add specific error for not subclass, if the archetype has a superclass? for (auto proto : paramArchetype->getConformsTo()) { - if (!CS.TC.conformsToProtocol(substitution, proto, CS.DC, - ConformanceCheckFlags::InExpression)) { + if (!TypeChecker::conformsToProtocol(substitution, proto, CS.DC, + ConformanceCheckFlags::InExpression)) { if (substitution->isEqual(argType)) { CS.TC.diagnose(badArgExpr->getLoc(), diag::cannot_convert_argument_value_protocol, diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index 438cbcceb8844..43402828d9512 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -72,25 +72,23 @@ enum CodableConformanceType { /// Returns whether the given type conforms to the given {En,De}codable /// protocol. /// -/// \param tc The typechecker to use in validating {En,De}codable conformance. -/// /// \param context The \c DeclContext the var declarations belong to. /// /// \param target The \c Type to validate. /// /// \param proto The \c ProtocolDecl to check conformance to. -static CodableConformanceType typeConformsToCodable(TypeChecker &tc, - DeclContext *context, +static CodableConformanceType typeConformsToCodable(DeclContext *context, Type target, bool isIUO, ProtocolDecl *proto) { target = context->mapTypeIntoContext(target); if (isIUO) - return typeConformsToCodable(tc, context, target->getOptionalObjectType(), + return typeConformsToCodable(context, target->getOptionalObjectType(), false, proto); - return tc.conformsToProtocol(target, proto, context, None) ? Conforms - : DoesNotConform; + return (TypeChecker::conformsToProtocol(target, proto, context, None) + ? Conforms + : DoesNotConform); } /// Returns whether the given variable conforms to the given {En,De}codable @@ -131,7 +129,7 @@ static CodableConformanceType varConformsToCodable(TypeChecker &tc, bool isIUO = varDecl->getAttrs().hasAttribute(); - return typeConformsToCodable(tc, context, varDecl->getValueInterfaceType(), + return typeConformsToCodable(context, varDecl->getValueInterfaceType(), isIUO, proto); } @@ -287,9 +285,9 @@ static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { // Ensure that the type we found conforms to the CodingKey protocol. auto *codingKeyProto = C.getProtocol(KnownProtocolKind::CodingKey); - if (!tc.conformsToProtocol(codingKeysType, codingKeyProto, - derived.getConformanceContext(), - None)) { + if (!TypeChecker::conformsToProtocol(codingKeysType, codingKeyProto, + derived.getConformanceContext(), + None)) { // If CodingKeys is a typealias which doesn't point to a valid nominal type, // codingKeysTypeDecl will be nullptr here. In that case, we need to warn on // the location of the usage, since there isn't an underlying type to @@ -1082,7 +1080,8 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) { if (auto *superclassDecl = classDecl->getSuperclassDecl()) { DeclName memberName; auto superType = superclassDecl->getDeclaredInterfaceType(); - if (tc.conformsToProtocol(superType, proto, superclassDecl, None)) { + if (TypeChecker::conformsToProtocol(superType, proto, superclassDecl, + None)) { // super.init(from:) must be accessible. memberName = cast(requirement)->getFullName(); } else { @@ -1097,8 +1096,8 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) { if (result.empty()) { // No super initializer for us to call. - tc.diagnose(superclassDecl, diag::decodable_no_super_init_here, - requirement->getFullName(), memberName); + superclassDecl->diagnose(diag::decodable_no_super_init_here, + requirement->getFullName(), memberName); return false; } else if (result.size() > 1) { // There are multiple results for this lookup. We'll end up producing a @@ -1111,22 +1110,21 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) { auto conformanceDC = derived.getConformanceContext(); if (!initializer->isDesignatedInit()) { // We must call a superclass's designated initializer. - tc.diagnose(initializer, - diag::decodable_super_init_not_designated_here, - requirement->getFullName(), memberName); + initializer->diagnose(diag::decodable_super_init_not_designated_here, + requirement->getFullName(), memberName); return false; } else if (!initializer->isAccessibleFrom(conformanceDC)) { // Cannot call an inaccessible method. auto accessScope = initializer->getFormalAccessScope(conformanceDC); - tc.diagnose(initializer, diag::decodable_inaccessible_super_init_here, - requirement->getFullName(), memberName, - accessScope.accessLevelForDiagnostics()); + initializer->diagnose(diag::decodable_inaccessible_super_init_here, + requirement->getFullName(), memberName, + accessScope.accessLevelForDiagnostics()); return false; } else if (initializer->getFailability() != OTK_None) { // We can't call super.init() if it's failable, since init(from:) // isn't failable. - tc.diagnose(initializer, diag::decodable_super_init_is_failable_here, - requirement->getFullName(), memberName); + initializer->diagnose(diag::decodable_super_init_is_failable_here, + requirement->getFullName(), memberName); return false; } } diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index 56aa16303a8ca..bffa7948a359e 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -1082,18 +1082,19 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) { // We can't form a Hashable conformance if Int isn't Hashable or // ExpressibleByIntegerLiteral. - if (!tc.conformsToProtocol(intType, - C.getProtocol(KnownProtocolKind::Hashable), - parentDC, None)) { - tc.diagnose(derived.ConformanceDecl, diag::broken_int_hashable_conformance); + if (!TypeChecker::conformsToProtocol(intType, + C.getProtocol(KnownProtocolKind::Hashable), + parentDC, None)) { + derived.ConformanceDecl->diagnose(diag::broken_int_hashable_conformance); return nullptr; } ProtocolDecl *intLiteralProto = C.getProtocol(KnownProtocolKind::ExpressibleByIntegerLiteral); - if (!tc.conformsToProtocol(intType, intLiteralProto, parentDC, None)) { - tc.diagnose(derived.ConformanceDecl, - diag::broken_int_integer_literal_convertible_conformance); + if (!TypeChecker::conformsToProtocol(intType, intLiteralProto, + parentDC, None)) { + derived.ConformanceDecl->diagnose( + diag::broken_int_integer_literal_convertible_conformance); return nullptr; } diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp index a97d95918002e..25f205b5df0f4 100644 --- a/lib/Sema/DerivedConformanceRawRepresentable.cpp +++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp @@ -421,7 +421,8 @@ deriveRawRepresentable_init(DerivedConformance &derived) { auto equatableProto = tc.getProtocol(enumDecl->getLoc(), KnownProtocolKind::Equatable); assert(equatableProto); - assert(tc.conformsToProtocol(rawType, equatableProto, enumDecl, None)); + assert(TypeChecker::conformsToProtocol(rawType, equatableProto, + enumDecl, None)); (void)equatableProto; (void)rawType; @@ -489,7 +490,8 @@ static bool canSynthesizeRawRepresentable(DerivedConformance &derived) { if (!equatableProto) return false; - if (!tc.conformsToProtocol(rawType, equatableProto, enumDecl, None)) + if (!TypeChecker::conformsToProtocol(rawType, equatableProto, + enumDecl, None)) return false; // There must be enum elements. diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index 5b66439ee4755..fd470139dca76 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -152,7 +152,7 @@ ValueDecl *DerivedConformance::getDerivableRequirement(TypeChecker &tc, auto proto = ctx.getProtocol(kind); if (!proto) return nullptr; - if (auto conformance = tc.conformsToProtocol( + if (auto conformance = TypeChecker::conformsToProtocol( nominal->getDeclaredInterfaceType(), proto, nominal, ConformanceCheckFlags::SkipConditionalRequirements)) { auto DC = conformance->getConcrete()->getDeclContext(); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 1723735d4f8c9..ac6f128c5170b 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -897,8 +897,8 @@ bool swift::isValidDynamicCallableMethod(FuncDecl *decl, DeclContext *DC, if (!hasKeywordArguments) { auto arrayLitProto = TC.Context.getProtocol(KnownProtocolKind::ExpressibleByArrayLiteral); - return TC.conformsToProtocol(argType, arrayLitProto, DC, - ConformanceCheckOptions()).hasValue(); + return TypeChecker::conformsToProtocol(argType, arrayLitProto, DC, + ConformanceCheckOptions()).hasValue(); } // If keyword arguments, check that argument type conforms to // `ExpressibleByDictionaryLiteral` and that the `Key` associated type @@ -907,15 +907,15 @@ bool swift::isValidDynamicCallableMethod(FuncDecl *decl, DeclContext *DC, TC.Context.getProtocol(KnownProtocolKind::ExpressibleByStringLiteral); auto dictLitProto = TC.Context.getProtocol(KnownProtocolKind::ExpressibleByDictionaryLiteral); - auto dictConf = TC.conformsToProtocol(argType, dictLitProto, DC, - ConformanceCheckOptions()); + auto dictConf = TypeChecker::conformsToProtocol(argType, dictLitProto, DC, + ConformanceCheckOptions()); if (!dictConf) return false; auto lookup = dictLitProto->lookupDirect(TC.Context.Id_Key); auto keyAssocType = cast(lookup[0])->getDeclaredInterfaceType(); auto keyType = dictConf.getValue().getAssociatedType(argType, keyAssocType); - return TC.conformsToProtocol(keyType, stringLitProtocol, DC, - ConformanceCheckOptions()).hasValue(); + return TypeChecker::conformsToProtocol(keyType, stringLitProtocol, DC, + ConformanceCheckOptions()).hasValue(); } /// Returns true if the given nominal type has a valid implementation of a @@ -1004,8 +1004,8 @@ bool swift::isValidStringDynamicMemberLookup(SubscriptDecl *decl, TC.Context.getProtocol(KnownProtocolKind::ExpressibleByStringLiteral); // If this is `subscript(dynamicMember: String*)` - return bool(TC.conformsToProtocol(paramType, stringLitProto, DC, - ConformanceCheckOptions())); + return bool(TypeChecker::conformsToProtocol(paramType, stringLitProto, DC, + ConformanceCheckOptions())); } bool swift::isValidKeyPathDynamicMemberLookup(SubscriptDecl *decl, @@ -1490,8 +1490,9 @@ void AttributeChecker::checkApplicationMainAttribute(DeclAttribute *attr, } if (!ApplicationDelegateProto || - !TC.conformsToProtocol(CD->getDeclaredType(), ApplicationDelegateProto, - CD, None)) { + !TypeChecker::conformsToProtocol(CD->getDeclaredType(), + ApplicationDelegateProto, + CD, None)) { TC.diagnose(attr->getLocation(), diag::attr_ApplicationMain_not_ApplicationDelegate, applicationMainKind); diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index fc67ed345b057..85b279332122d 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -2627,10 +2627,10 @@ static bool isIntegerOrFloatingPointType(Type ty, DeclContext *DC, if (!integerType || !floatingType) return false; return - TC.conformsToProtocol(ty, integerType, DC, - ConformanceCheckFlags::InExpression) || - TC.conformsToProtocol(ty, floatingType, DC, - ConformanceCheckFlags::InExpression); + TypeChecker::conformsToProtocol(ty, integerType, DC, + ConformanceCheckFlags::InExpression) || + TypeChecker::conformsToProtocol(ty, floatingType, DC, + ConformanceCheckFlags::InExpression); } diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 07f78f97e0bba..413872023e728 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -1993,7 +1993,7 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) { options |= ConformanceCheckFlags::InExpression; options |= ConformanceCheckFlags::SkipConditionalRequirements; - auto result = TC.conformsToProtocol(type, protocol, DC, options); + auto result = TypeChecker::conformsToProtocol(type, protocol, DC, options); if (!result || !result->isConcrete()) return nullptr; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 35e39b60c2e7f..0cf3c05f11b74 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1488,7 +1488,8 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) { // primitive literal protocols. auto conformsToProtocol = [&](KnownProtocolKind protoKind) { ProtocolDecl *proto = TC.getProtocol(ED->getLoc(), protoKind); - return TC.conformsToProtocol(rawTy, proto, ED->getDeclContext(), None); + return TypeChecker::conformsToProtocol(rawTy, proto, + ED->getDeclContext(), None); }; static auto otherLiteralProtocolKinds = { @@ -4486,7 +4487,7 @@ static void finalizeType(TypeChecker &TC, NominalTypeDecl *nominal) { TC.requestSuperclassLayout(CD); auto forceConformance = [&](ProtocolDecl *protocol) { - if (auto ref = TC.conformsToProtocol( + if (auto ref = TypeChecker::conformsToProtocol( CD->getDeclaredInterfaceType(), protocol, CD, ConformanceCheckFlags::SkipConditionalRequirements, SourceLoc())) { @@ -4949,10 +4950,10 @@ static void diagnoseClassWithoutInitializers(TypeChecker &tc, ASTContext &C = tc.Context; auto *decodableProto = C.getProtocol(KnownProtocolKind::Decodable); auto superclassType = superclassDecl->getDeclaredInterfaceType(); - if (auto ref = tc.conformsToProtocol(superclassType, decodableProto, - superclassDecl, - ConformanceCheckOptions(), - SourceLoc())) { + if (auto ref = TypeChecker::conformsToProtocol(superclassType, decodableProto, + superclassDecl, + ConformanceCheckOptions(), + SourceLoc())) { // super conforms to Decodable, so we've failed to inherit init(from:). // Let's suggest overriding it here. // diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 9b87eee3c62ca..d849f289d7bde 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -231,11 +231,9 @@ namespace { // Dig out the protocol conformance. auto *foundProto = cast(foundDC); - auto resolver = DC->getASTContext().getLazyResolver(); - assert(resolver && "Need an active resolver"); - auto &tc = *static_cast(resolver); - auto conformance = tc.conformsToProtocol(conformingType, foundProto, DC, - conformanceOptions); + auto conformance = TypeChecker::conformsToProtocol(conformingType, + foundProto, DC, + conformanceOptions); if (!conformance) { // If there's no conformance, we have an existential // and we found a member from one of the protocols, and diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index c084baeaa9d25..2e7ab575646bd 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1718,7 +1718,7 @@ checkIndividualConformance(NormalProtocolConformance *conformance, // Check that T conforms to all inherited protocols. for (auto InheritedProto : Proto->getInheritedProtocols()) { auto InheritedConformance = - TC.conformsToProtocol( + TypeChecker::conformsToProtocol( T, InheritedProto, DC, ConformanceCheckFlags::SkipConditionalRequirements, ComplainLoc); @@ -2932,7 +2932,8 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) { // a member that could in turn satisfy *this* requirement. auto derivableProto = cast(derivable->getDeclContext()); if (auto conformance = - TC.conformsToProtocol(Adoptee, derivableProto, DC, None)) { + TypeChecker::conformsToProtocol(Adoptee, derivableProto, + DC, None)) { if (conformance->isConcrete()) (void)conformance->getConcrete()->getWitnessDecl(derivable, &TC); } @@ -3313,7 +3314,7 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc, // Check protocol conformances. for (auto reqProto : genericSig->getConformsTo(depTy)) { - if (!tc.conformsToProtocol( + if (!TypeChecker::conformsToProtocol( contextType, reqProto, dc, ConformanceCheckFlags::SkipConditionalRequirements)) return CheckTypeWitnessResult(reqProto->getDeclaredType()); diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 7bf44b6ff2166..8595602fddf88 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -970,7 +970,7 @@ Type AssociatedTypeInference::substCurrentTypeWitnesses(Type type) { // If that failed, check whether it's because of the conformance we're // evaluating. auto localConformance - = tc.conformsToProtocol( + = TypeChecker::conformsToProtocol( baseTy, assocType->getProtocol(), dc, ConformanceCheckFlags::SkipConditionalRequirements); if (!localConformance || localConformance->isAbstract() || diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index a07157ffa36b9..1cdfc4fc54083 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -739,9 +739,9 @@ class StmtChecker : public StmtVisitor { { Type sequenceType = sequence->getType(); auto conformance = - TC.conformsToProtocol(sequenceType, sequenceProto, DC, - ConformanceCheckFlags::InExpression, - sequence->getLoc()); + TypeChecker::conformsToProtocol(sequenceType, sequenceProto, DC, + ConformanceCheckFlags::InExpression, + sequence->getLoc()); if (!conformance) return nullptr; @@ -789,9 +789,9 @@ class StmtChecker : public StmtVisitor { // FIXME: Would like to customize the diagnostic emitted in // conformsToProtocol(). auto genConformance = - TC.conformsToProtocol(generatorTy, generatorProto, DC, - ConformanceCheckFlags::InExpression, - sequence->getLoc()); + TypeChecker::conformsToProtocol(generatorTy, generatorProto, DC, + ConformanceCheckFlags::InExpression, + sequence->getLoc()); if (!genConformance) return nullptr; From 823ba0bb7352732a02395c49390f1fcfb6322205 Mon Sep 17 00:00:00 2001 From: Parker Schuh Date: Thu, 28 Mar 2019 11:14:18 -0700 Subject: [PATCH 2/4] Convert ObjectLiteralExpr to not use tc.callWitness() or generate a SemanticExpr. For reference, all other literal types except dictionaries and string interpolation have been converted over to this form. --- include/swift/AST/Expr.h | 10 ++++++ lib/AST/ASTDumper.cpp | 2 ++ lib/SILGen/SILGenExpr.cpp | 9 ++++- lib/Sema/CSApply.cpp | 29 ++++------------ lib/Sema/MiscDiagnostics.cpp | 4 +++ test/SILGen/literals.swift | 65 ++++++++++++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 24 deletions(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index e6af2df8196bf..7af6c2080b537 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -1135,6 +1135,7 @@ class ObjectLiteralExpr final Expr *Arg; Expr *SemanticExpr; SourceLoc PoundLoc; + ConcreteDeclRef Initializer; ObjectLiteralExpr(SourceLoc PoundLoc, LiteralKind LitKind, Expr *Arg, @@ -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; } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 2a205bcd84592..e6844632658fe 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1967,6 +1967,8 @@ class PrintExpr : public ExprVisitor { 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()); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index e1d02a526018d..7a57c88145ffa 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -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(init.getDecl()); + AnyFunctionType *fnTy = decl->getMethodInterfaceType() + .subst(init.getSubstitutions()) + ->getAs(); + PreparedArguments args(fnTy->getParams(), E->getArg()); + return SGF.emitApplyAllocatingInitializer(SILLocation(E), init, + std::move(args), E->getType(), C); } RValue RValueEmitter:: diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 912e24b11d170..6ff140658bd53 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2211,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. @@ -2236,30 +2235,14 @@ namespace { ConformanceCheckFlags::InExpression); assert(conformance && "object literal type conforms to protocol"); - Expr *base = TypeExpr::createImplicitHack(expr->getLoc(), conformingType, - ctx); - cs.cacheExprTypes(base); - - SmallVector args; - if (!isa(expr->getArg())) - return nullptr; - auto tupleArg = cast(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(witness.getDecl())) + return nullptr; + expr->setInitializer(witness); return expr; } diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 9d6361bcee2cc..95b6bc739e9a7 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -124,6 +124,10 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, if (isa(Base)) checkUseOfMetaTypeName(Base); + if (auto *OLE = dyn_cast(E)) { + CallArgs.insert(OLE->getArg()); + } + if (auto *SE = dyn_cast(E)) CallArgs.insert(SE->getIndex()); diff --git a/test/SILGen/literals.swift b/test/SILGen/literals.swift index 47471cdde1d9d..722e70ff5aa14 100644 --- a/test/SILGen/literals.swift +++ b/test/SILGen/literals.swift @@ -255,3 +255,68 @@ func makeBasic() -> T { return T() } func throwingElement() throws -> [T] { return try [makeBasic(), makeThrowing()] } + +struct Color: _ExpressibleByColorLiteral { + init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float) {} +} + +// CHECK-LABEL: sil hidden [ossa] @$s8literals16makeColorLiteralAA0C0VyF : $@convention(thin) () -> Color { +// CHECK: [[COLOR_METATYPE:%.*]] = metatype $@thin Color.Type +// CHECK: [[VALUE:%.*]] = float_literal $Builtin.FPIEEE80, 0x3FFFADD2F1A9FBE76C8B +// CHECK: [[METATYPE:%.*]] = metatype $@thin Float.Type +// CHECK: [[FN:%.*]] = function_ref @$sSf20_builtinFloatLiteralSfBf80__tcfC +// CHECK: [[R:%.*]] = apply [[FN]]([[VALUE]], [[METATYPE]]) : $@convention(method) (Builtin.FPIEEE80, @thin Float.Type) -> Float + +// CHECK: [[VALUE:%.*]] = float_literal $Builtin.FPIEEE80, 0xBFFB978D4FDF3B645A1D +// CHECK: [[METATYPE:%.*]] = metatype $@thin Float.Type +// CHECK: [[FN:%.*]] = function_ref @$sSf20_builtinFloatLiteralSfBf80__tcfC +// CHECK: [[G:%.*]] = apply [[FN]]([[VALUE]], [[METATYPE]]) : $@convention(method) (Builtin.FPIEEE80, @thin Float.Type) -> Float + +// CHECK: [[VALUE:%.*]] = float_literal $Builtin.FPIEEE80, 0xBFF8C49BA5E353F7CED9 +// CHECK: [[METATYPE:%.*]] = metatype $@thin Float.Type +// CHECK: [[FN:%.*]] = function_ref @$sSf20_builtinFloatLiteralSfBf80__tcfC +// CHECK: [[B:%.*]] = apply [[FN]]([[VALUE]], [[METATYPE]]) : $@convention(method) (Builtin.FPIEEE80, @thin Float.Type) -> Float + +// CHECK: [[VALUE:%.*]] = float_literal $Builtin.FPIEEE80, 0x3FFF8000000000000000 +// CHECK: [[METATYPE:%.*]] = metatype $@thin Float.Type +// CHECK: [[FN:%.*]] = function_ref @$sSf20_builtinFloatLiteralSfBf80__tcfC +// CHECK: [[A:%.*]] = apply [[FN]]([[VALUE]], [[METATYPE]]) : $@convention(method) (Builtin.FPIEEE80, @thin Float.Type) -> Float + +// CHECK: [[FN:%.*]] = function_ref @$s8literals5ColorV16_colorLiteralRed5green4blue5alphaACSf_S3ftcfC : $@convention(method) (Float, Float, Float, Float, @thin Color.Type) -> Color +// CHECK: [[LIT:%.*]] = apply [[FN]]([[R]], [[G]], [[B]], [[A]], [[COLOR_METATYPE]]) : $@convention(method) (Float, Float, Float, Float, @thin Color.Type) -> Color +// CHECK: return [[LIT]] : $Color +func makeColorLiteral() -> Color { + return #colorLiteral(red: 1.358, green: -0.074, blue: -0.012, alpha: 1.0) +} + +struct Image: _ExpressibleByImageLiteral { + init(imageLiteralResourceName: String) {} +} + +func makeTmpString() -> String { return "" } + +// CHECK-LABEL: sil hidden [ossa] @$s8literals16makeImageLiteralAA0C0VyF : $@convention(thin) () -> Image +// CHECK: [[METATYPE:%.*]] = metatype $@thin Image.Type +// CHECK: [[FN:%.*]] = function_ref @$s8literals13makeTmpStringSSyF : $@convention(thin) () -> @owned String +// CHECK: [[STR:%.*]] = apply [[FN]]() : $@convention(thin) () -> @owned String +// CHECK: [[FN:%.*]] = function_ref @$s8literals5ImageV24imageLiteralResourceNameACSS_tcfC : $@convention(method) (@owned String, @thin Image.Type) -> Image +// CHECK: [[LIT:%.*]] = apply [[FN]]([[STR]], [[METATYPE]]) : $@convention(method) (@owned String, @thin Image.Type) -> Image +// CHECK: return [[LIT]] : $Image +func makeImageLiteral() -> Image { + return #imageLiteral(resourceName: makeTmpString()) +} + +struct FileReference: _ExpressibleByFileReferenceLiteral { + init(fileReferenceLiteralResourceName: String) {} +} + +// CHECK-LABEL: sil hidden [ossa] @$s8literals24makeFileReferenceLiteralAA0cD0VyF : $@convention(thin) () -> FileReference +// CHECK: [[METATYPE:%.*]] = metatype $@thin FileReference.Type +// CHECK: [[FN:%.*]] = function_ref @$s8literals13makeTmpStringSSyF : $@convention(thin) () -> @owned String +// CHECK: [[STR:%.*]] = apply [[FN]]() : $@convention(thin) () -> @owned String +// CHECK: [[FN:%.*]] = function_ref @$s8literals13FileReferenceV04fileC19LiteralResourceNameACSS_tcfC +// CHECK: [[LIT:%.*]] = apply [[FN]]([[STR]], [[METATYPE]]) : $@convention(method) (@owned String, @thin FileReference.Type) -> FileReference +// CHECK: return [[LIT]] : $FileReference +func makeFileReferenceLiteral() -> FileReference { + return #fileLiteral(resourceName: makeTmpString()) +} From 6e90172010d810b5a831b811a3deae884ff6d4de Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 11 Jun 2019 02:32:48 -0700 Subject: [PATCH 3/4] AST: Remove unnecessary fast path --- lib/AST/ProtocolConformance.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 13dd5944ec3c1..88d17346b4c3f 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -1120,11 +1120,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); } From ae5a427193a42b9e7427d3f12453d3c03a9dcb12 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 11 Jun 2019 02:35:25 -0700 Subject: [PATCH 4/4] AST: Fix ProtocolConformance::getWitnessDeclRef() This method was only ever called with non-generic witnesses, because it assumed the substitutions stored in the witness would always be derived from the conforming type. There were two cases where this wasn't the case though: 1) If the witness is itself generic 2) The witness was defined in a protocol extension and the conforming type is a non-final class In all cases, the SubstitutionMap stored in a Witness always uses the 'synthetic environment'. In some cases, the 'synthetic environment' is the generic environment of the witness. But in 1) and 2) it was different. While 1) never occurred because we never used this method to look up witnesses for generic requirements, 2) could happen. --- lib/AST/ProtocolConformance.cpp | 19 +++++++++++++++++-- test/SILGen/literals.swift | 23 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 88d17346b4c3f..d17a89fb5355f 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -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(witnessDecl)) + 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(); } diff --git a/test/SILGen/literals.swift b/test/SILGen/literals.swift index 722e70ff5aa14..df38a0e41bb29 100644 --- a/test/SILGen/literals.swift +++ b/test/SILGen/literals.swift @@ -320,3 +320,26 @@ struct FileReference: _ExpressibleByFileReferenceLiteral { func makeFileReferenceLiteral() -> FileReference { return #fileLiteral(resourceName: makeTmpString()) } + +class ReferenceColor { required init() {} } + +protocol Silly { + init() + init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float) +} + +extension Silly { + init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float) { + self.init() + } +} + +extension ReferenceColor : Silly, _ExpressibleByColorLiteral {} + +func makeColorLiteral() -> ReferenceColor { + return #colorLiteral(red: 1.358, green: -0.074, blue: -0.012, alpha: 1.0) +} + +// CHECK-LABEL: sil hidden [ossa] @$s8literals16makeColorLiteralAA09ReferenceC0CyxGylF : $@convention(thin) () -> @owned ReferenceColor +// CHECK: [[FN:%.*]] = function_ref @$s8literals5SillyPAAE16_colorLiteralRed5green4blue5alphaxSf_S3ftcfC : $@convention(method) <τ_0_0 where τ_0_0 : Silly> (Float, Float, Float, Float, @thick τ_0_0.Type) -> @out τ_0_0 +// CHECK: apply [[FN]]>(