diff --git a/lib/Sema/CSStep.cpp b/lib/Sema/CSStep.cpp index 7a7baff3a6774..5cb3ccd17aacb 100644 --- a/lib/Sema/CSStep.cpp +++ b/lib/Sema/CSStep.cpp @@ -616,7 +616,7 @@ bool IsDeclRefinementOfRequest::evaluate(Evaluator &evaluator, genericSignatureB.getRequirements(), QueryTypeSubstitutionMap{ substMap }); - if (result != RequirementCheckResult::Success) + if (result != CheckGenericArgumentsResult::Success) return false; return substTypeA->isEqual(substTypeB); diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index caaddb30cc05f..63daaa7e6cc47 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -749,7 +749,7 @@ createDesignatedInitOverride(ClassDecl *classDecl, return GenericEnvironment::mapTypeIntoContext( genericEnv, substType); }); - if (checkResult != RequirementCheckResult::Success) + if (checkResult != CheckGenericArgumentsResult::Success) return nullptr; } diff --git a/lib/Sema/IDETypeCheckingRequests.cpp b/lib/Sema/IDETypeCheckingRequests.cpp index f02d0bb87182d..25fc86716e4c5 100644 --- a/lib/Sema/IDETypeCheckingRequests.cpp +++ b/lib/Sema/IDETypeCheckingRequests.cpp @@ -134,9 +134,10 @@ static bool isExtensionAppliedInternal(const DeclContext *DC, Type BaseTy, auto *module = DC->getParentModule(); SubstitutionMap substMap = BaseTy->getContextSubstitutionMap( module, ED->getExtendedNominal()); - return TypeChecker::checkGenericArguments( - module, genericSig.getRequirements(), - QuerySubstitutionMap{substMap}) == RequirementCheckResult::Success; + return TypeChecker::checkGenericArguments(module, + genericSig.getRequirements(), + QuerySubstitutionMap{substMap}) == + CheckGenericArgumentsResult::Success; } static bool isMemberDeclAppliedInternal(const DeclContext *DC, Type BaseTy, @@ -170,9 +171,10 @@ static bool isMemberDeclAppliedInternal(const DeclContext *DC, Type BaseTy, // Note: we treat substitution failure as success, to avoid tripping // up over generic parameters introduced by the declaration itself. - return TypeChecker::checkGenericArguments( - module, genericSig.getRequirements(), - QuerySubstitutionMap{substMap}) != RequirementCheckResult::Failure; + return TypeChecker::checkGenericArguments(module, + genericSig.getRequirements(), + QuerySubstitutionMap{substMap}) != + CheckGenericArgumentsResult::RequirementFailure; } bool diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 0617961ce5f41..1bfcbcf08ab6a 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2999,7 +2999,7 @@ TypeEraserHasViableInitRequest::evaluate(Evaluator &evaluator, return getSubstitution(type); }); - if (result != RequirementCheckResult::Success) { + if (result != CheckGenericArgumentsResult::Success) { unviable.push_back( std::make_tuple(init, UnviableReason::UnsatisfiedRequirements, genericParamType)); diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 5b79b79d48a8d..d3f31706626fd 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -30,55 +30,6 @@ using namespace swift; -/// -/// Common code for generic functions, generic types -/// - -std::string -TypeChecker::gatherGenericParamBindingsText( - ArrayRef types, - TypeArrayView genericParams, - TypeSubstitutionFn substitutions) { - llvm::SmallPtrSet knownGenericParams; - for (auto type : types) { - if (type.isNull()) continue; - - type.visit([&](Type type) { - if (auto gp = type->getAs()) { - knownGenericParams.insert( - gp->getCanonicalType()->castTo()); - } - }); - } - - if (knownGenericParams.empty()) - return ""; - - SmallString<128> result; - for (auto gp : genericParams) { - auto canonGP = gp->getCanonicalType()->castTo(); - if (!knownGenericParams.count(canonGP)) - continue; - - if (result.empty()) - result += " [with "; - else - result += ", "; - result += gp->getName().str(); - result += " = "; - - auto type = substitutions(canonGP); - if (!type) - return ""; - - result += type.getString(); - } - - result += "]"; - return result.str().str(); -} - - // // Generic functions // @@ -817,129 +768,204 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, /// Checking bound generic type arguments /// -RequirementCheckResult TypeChecker::checkGenericArguments( - ModuleDecl *module, SourceLoc loc, SourceLoc noteLoc, Type owner, +/// Create a text string that describes the bindings of generic parameters +/// that are relevant to the given set of types, e.g., +/// "[with T = Bar, U = Wibble]". +/// +/// \param types The types that will be scanned for generic type parameters, +/// which will be used in the resulting type. +/// +/// \param genericParams The generic parameters to use to resugar any +/// generic parameters that occur within the types. +/// +/// \param substitutions The generic parameter -> generic argument +/// substitutions that will have been applied to these types. +/// These are used to produce the "parameter = argument" bindings in the test. +static std::string gatherGenericParamBindingsText( + ArrayRef types, TypeArrayView genericParams, + TypeSubstitutionFn substitutions) { + llvm::SmallPtrSet knownGenericParams; + for (auto type : types) { + if (type.isNull()) continue; + + type.visit([&](Type type) { + if (auto gp = type->getAs()) { + knownGenericParams.insert( + gp->getCanonicalType()->castTo()); + } + }); + } + + if (knownGenericParams.empty()) + return ""; + + SmallString<128> result; + for (auto gp : genericParams) { + auto canonGP = gp->getCanonicalType()->castTo(); + if (!knownGenericParams.count(canonGP)) + continue; + + if (result.empty()) + result += " [with "; + else + result += ", "; + result += gp->getName().str(); + result += " = "; + + auto type = substitutions(canonGP); + if (!type) + return ""; + + result += type.getString(); + } + + result += "]"; + return result.str().str(); +} + +void TypeChecker::diagnoseRequirementFailure( + const CheckGenericArgumentsResult::RequirementFailureInfo &reqFailureInfo, + SourceLoc errorLoc, SourceLoc noteLoc, Type targetTy, TypeArrayView genericParams, - ArrayRef requirements, - TypeSubstitutionFn substitutions, - SubstOptions options) { - bool valid = true; + TypeSubstitutionFn substitutions, ModuleDecl *module) { + assert(errorLoc.isValid() && noteLoc.isValid()); - struct RequirementSet { - ArrayRef Requirements; - SmallVector Parents; - }; + const auto &req = reqFailureInfo.Req; + const auto &substReq = reqFailureInfo.SubstReq; - SmallVector pendingReqs; - pendingReqs.push_back({requirements, {}}); + Diag diagnostic; + Diag diagnosticNote; - ASTContext &ctx = module->getASTContext(); - while (!pendingReqs.empty()) { - auto current = pendingReqs.pop_back_val(); - - for (const auto &rawReq : current.Requirements) { - auto req = rawReq; - if (current.Parents.empty()) { - auto substed = rawReq.subst( - substitutions, LookUpConformanceInModule(module), options); - if (!substed) { - // Another requirement will fail later; just continue. - valid = false; - continue; - } + const auto reqKind = req.getKind(); + switch (reqKind) { + case RequirementKind::Conformance: { + diagnoseConformanceFailure(substReq.getFirstType(), + substReq.getProtocolDecl(), module, errorLoc); - req = *substed; - } + if (reqFailureInfo.ReqPath.empty()) + return; - ArrayRef conditionalRequirements; - if (req.isSatisfied(conditionalRequirements, /*allowMissing=*/true)) { - if (!conditionalRequirements.empty()) { - assert(req.getKind() == RequirementKind::Conformance); + diagnostic = diag::type_does_not_conform_owner; + diagnosticNote = diag::type_does_not_inherit_or_conform_requirement; + break; + } - auto history = current.Parents; - history.push_back({req.getFirstType(), req.getProtocolDecl()}); - pendingReqs.push_back({conditionalRequirements, std::move(history)}); - } - continue; - } + case RequirementKind::Layout: + diagnostic = diag::type_is_not_a_class; + diagnosticNote = diag::anyobject_requirement; + break; - if (loc.isValid()) { - Diag diagnostic; - Diag diagnosticNote; + case RequirementKind::Superclass: + diagnostic = diag::type_does_not_inherit; + diagnosticNote = diag::type_does_not_inherit_or_conform_requirement; + break; + + case RequirementKind::SameType: + diagnostic = diag::types_not_equal; + diagnosticNote = diag::types_not_equal_requirement; + break; + } - switch (req.getKind()) { - case RequirementKind::Conformance: { - diagnoseConformanceFailure(req.getFirstType(), req.getProtocolDecl(), - module, loc); + Type secondTy, substSecondTy; + if (req.getKind() != RequirementKind::Layout) { + secondTy = req.getSecondType(); + substSecondTy = substReq.getSecondType(); + } - if (current.Parents.empty()) - return RequirementCheckResult::Failure; + ASTContext &ctx = module->getASTContext(); + // FIXME: Poor source-location information. + ctx.Diags.diagnose(errorLoc, diagnostic, targetTy, substReq.getFirstType(), + substSecondTy); - diagnostic = diag::type_does_not_conform_owner; - diagnosticNote = diag::type_does_not_inherit_or_conform_requirement; - break; - } + const auto genericParamBindingsText = gatherGenericParamBindingsText( + {req.getFirstType(), secondTy}, genericParams, substitutions); - case RequirementKind::Layout: - diagnostic = diag::type_is_not_a_class; - diagnosticNote = diag::anyobject_requirement; - break; + ctx.Diags.diagnose(noteLoc, diagnosticNote, req.getFirstType(), secondTy, + genericParamBindingsText); - case RequirementKind::Superclass: - diagnostic = diag::type_does_not_inherit; - diagnosticNote = diag::type_does_not_inherit_or_conform_requirement; - break; + ParentConditionalConformance::diagnoseConformanceStack( + ctx.Diags, noteLoc, reqFailureInfo.ReqPath); +} - case RequirementKind::SameType: - diagnostic = diag::types_not_equal; - diagnosticNote = diag::types_not_equal_requirement; - break; - } +CheckGenericArgumentsResult TypeChecker::checkGenericArgumentsForDiagnostics( + ModuleDecl *module, ArrayRef requirements, + TypeSubstitutionFn substitutions) { + using ParentConditionalConformances = + SmallVector; - Type rawSecondType, secondType; - if (req.getKind() != RequirementKind::Layout) { - rawSecondType = rawReq.getSecondType(); - secondType = req.getSecondType(); - } + struct WorklistItem { + /// The set of requirements to check. These are either the primary set + /// of requirements, or the conditional requirements of the last conformance + /// in \c ReqsPath (if any). + ArrayRef Requirements; - // FIXME: Poor source-location information. - ctx.Diags.diagnose(loc, diagnostic, owner, - req.getFirstType(), secondType); + /// The chain of conditional conformances that leads to the above + /// requirement set. + ParentConditionalConformances ReqsPath; - std::string genericParamBindingsText; - if (!genericParams.empty()) { - genericParamBindingsText = - gatherGenericParamBindingsText( - {rawReq.getFirstType(), rawSecondType}, - genericParams, substitutions); + WorklistItem(ArrayRef Requirements, + ParentConditionalConformances ReqsPath) + : Requirements(Requirements), ReqsPath(ReqsPath) {} + }; + + bool hadSubstFailure = false; + SmallVector worklist; + + worklist.emplace_back(requirements, ParentConditionalConformances{}); + while (!worklist.empty()) { + const auto item = worklist.pop_back_val(); + + const bool isPrimaryReq = item.ReqsPath.empty(); + for (const auto &req : item.Requirements) { + Requirement substReq = req; + if (isPrimaryReq) { + // Primary requirements do not have substitutions applied. + if (auto resolved = + req.subst(substitutions, LookUpConformanceInModule(module))) { + substReq = *resolved; + } else { + // Another requirement might fail later; just continue. + hadSubstFailure = true; + continue; } - ctx.Diags.diagnose(noteLoc, diagnosticNote, - rawReq.getFirstType(), rawSecondType, - genericParamBindingsText); + } - ParentConditionalConformance::diagnoseConformanceStack( - ctx.Diags, noteLoc, current.Parents); + ArrayRef conditionalRequirements; + if (!substReq.isSatisfied(conditionalRequirements, + /*allowMissing=*/true)) { + return CheckGenericArgumentsResult::createRequirementFailure( + req, substReq, std::move(item.ReqsPath)); } - return RequirementCheckResult::Failure; + if (conditionalRequirements.empty()) { + continue; + } + + assert(req.getKind() == RequirementKind::Conformance); + + auto reqsPath = item.ReqsPath; + reqsPath.push_back({substReq.getFirstType(), substReq.getProtocolDecl()}); + + worklist.emplace_back(conditionalRequirements, std::move(reqsPath)); } } - if (valid) - return RequirementCheckResult::Success; - return RequirementCheckResult::SubstitutionFailure; + if (hadSubstFailure) { + return CheckGenericArgumentsResult::createSubstitutionFailure(); + } + + return CheckGenericArgumentsResult::createSuccess(); } -RequirementCheckResult -TypeChecker::checkGenericArguments(ModuleDecl *module, - ArrayRef requirements, - TypeSubstitutionFn substitutions) { +CheckGenericArgumentsResult::Kind TypeChecker::checkGenericArguments( + ModuleDecl *module, ArrayRef requirements, + TypeSubstitutionFn substitutions, SubstOptions options) { SmallVector worklist; bool valid = true; for (auto req : requirements) { if (auto resolved = req.subst(substitutions, - LookUpConformanceInModule(module))) { + LookUpConformanceInModule(module), options)) { worklist.push_back(*resolved); } else { valid = false; @@ -950,15 +976,15 @@ TypeChecker::checkGenericArguments(ModuleDecl *module, auto req = worklist.pop_back_val(); ArrayRef conditionalRequirements; if (!req.isSatisfied(conditionalRequirements, /*allowMissing=*/true)) - return RequirementCheckResult::Failure; + return CheckGenericArgumentsResult::RequirementFailure; worklist.append(conditionalRequirements.begin(), conditionalRequirements.end()); } if (valid) - return RequirementCheckResult::Success; - return RequirementCheckResult::SubstitutionFailure; + return CheckGenericArgumentsResult::Success; + return CheckGenericArgumentsResult::SubstitutionFailure; } Requirement diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 465f4a6fa84b3..38777e107e868 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -4942,20 +4942,13 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() { auto proto = Conformance->getProtocol(); auto &diags = proto->getASTContext().Diags; - auto DC = Conformance->getDeclContext(); + auto *const module = DC->getParentModule(); auto substitutingType = DC->mapTypeIntoContext(Conformance->getType()); auto substitutions = SubstitutionMap::getProtocolSubstitutions( proto, substitutingType, ProtocolConformanceRef(Conformance)); auto reqSig = proto->getRequirementSignature().getRequirements(); - auto result = TypeChecker::checkGenericArguments( - DC->getParentModule(), Loc, Loc, - // FIXME: maybe this should be the conformance's type - proto->getDeclaredInterfaceType(), - { proto->getSelfInterfaceType() }, - reqSig, QuerySubstitutionMap{substitutions}); - // Non-final classes should not be able to conform to protocols with a // same-type requirement on 'Self', since such a conformance would no // longer be covariant. For now, this is a warning. Once this becomes @@ -4970,23 +4963,31 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() { } } + const auto result = TypeChecker::checkGenericArgumentsForDiagnostics( + module, reqSig, QuerySubstitutionMap{substitutions}); switch (result) { - case RequirementCheckResult::Success: + case CheckGenericArgumentsResult::Success: // Go on to check exportability. break; - case RequirementCheckResult::Failure: - Conformance->setInvalid(); - return; - - case RequirementCheckResult::SubstitutionFailure: + case CheckGenericArgumentsResult::RequirementFailure: + case CheckGenericArgumentsResult::SubstitutionFailure: // Diagnose the failure generically. // FIXME: Would be nice to give some more context here! if (!Conformance->isInvalid()) { diags.diagnose(Loc, diag::type_does_not_conform, Adoptee, Proto->getDeclaredInterfaceType()); + + if (result == CheckGenericArgumentsResult::RequirementFailure) { + TypeChecker::diagnoseRequirementFailure( + result.getRequirementFailureInfo(), Loc, Loc, + proto->getDeclaredInterfaceType(), {proto->getSelfInterfaceType()}, + QuerySubstitutionMap{substitutions}, module); + } + Conformance->setInvalid(); + AlreadyComplained = true; } return; } @@ -5678,11 +5679,11 @@ TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M, M, *condReqs, [](SubstitutableType *dependentType) { return Type(dependentType); }); switch (conditionalCheckResult) { - case RequirementCheckResult::Success: + case CheckGenericArgumentsResult::Success: break; - case RequirementCheckResult::Failure: - case RequirementCheckResult::SubstitutionFailure: + case CheckGenericArgumentsResult::RequirementFailure: + case CheckGenericArgumentsResult::SubstitutionFailure: return ProtocolConformanceRef::forInvalid(); } } diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 5b9642fd47b8c..af36dcf6c8fcf 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -1131,20 +1131,16 @@ bool AssociatedTypeInference::checkCurrentTypeWitnesses( auto requirements = proto->getRequirementSignature().getRequirements(); sanitizeProtocolRequirements(proto, requirements, sanitizedRequirements); - auto result = - TypeChecker::checkGenericArguments(dc->getParentModule(), SourceLoc(), - SourceLoc(), typeInContext, - { proto->getSelfInterfaceType() }, - sanitizedRequirements, - QuerySubstitutionMap{substitutions}, - options); - switch (result) { - case RequirementCheckResult::Failure: + + switch (TypeChecker::checkGenericArguments( + dc->getParentModule(), sanitizedRequirements, + QuerySubstitutionMap{substitutions}, options)) { + case CheckGenericArgumentsResult::RequirementFailure: ++NumSolutionStatesFailedCheck; return true; - case RequirementCheckResult::Success: - case RequirementCheckResult::SubstitutionFailure: + case CheckGenericArgumentsResult::Success: + case CheckGenericArgumentsResult::SubstitutionFailure: break; } @@ -1180,16 +1176,13 @@ bool AssociatedTypeInference::checkConstrainedExtension(ExtensionDecl *ext) { SubstOptions options = getSubstOptionsWithCurrentTypeWitnesses(); switch (TypeChecker::checkGenericArguments( - dc->getParentModule(), SourceLoc(), SourceLoc(), adoptee, - ext->getGenericSignature().getGenericParams(), - ext->getGenericSignature().getRequirements(), - QueryTypeSubstitutionMap{subs}, - options)) { - case RequirementCheckResult::Success: - case RequirementCheckResult::SubstitutionFailure: + dc->getParentModule(), ext->getGenericSignature().getRequirements(), + QueryTypeSubstitutionMap{subs}, options)) { + case CheckGenericArgumentsResult::Success: + case CheckGenericArgumentsResult::SubstitutionFailure: return false; - case RequirementCheckResult::Failure: + case CheckGenericArgumentsResult::RequirementFailure: return true; } llvm_unreachable("unhandled result"); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index b2e99abc52987..73e8804ccb4a5 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -518,28 +518,32 @@ bool TypeChecker::checkContextualRequirements(GenericTypeDecl *decl, const auto subMap = parentTy->getContextSubstitutions(decl->getDeclContext()); const auto genericSig = decl->getGenericSignature(); - const auto result = - TypeChecker::checkGenericArguments( - module, loc, noteLoc, - decl->getDeclaredInterfaceType(), - genericSig.getGenericParams(), - genericSig.getRequirements(), - [&](SubstitutableType *type) -> Type { - auto result = QueryTypeSubstitutionMap{subMap}(type); - if (result->hasTypeParameter()) { - if (contextSig) { - auto *genericEnv = contextSig.getGenericEnvironment(); - return genericEnv->mapTypeIntoContext(result); - } - } - return result; - }); + const auto substitutions = [&](SubstitutableType *type) -> Type { + auto result = QueryTypeSubstitutionMap{subMap}(type); + if (result->hasTypeParameter()) { + if (contextSig) { + auto *genericEnv = contextSig.getGenericEnvironment(); + return genericEnv->mapTypeIntoContext(result); + } + } + return result; + }; + const auto result = TypeChecker::checkGenericArgumentsForDiagnostics( + module, genericSig.getRequirements(), substitutions); switch (result) { - case RequirementCheckResult::Failure: - case RequirementCheckResult::SubstitutionFailure: + case CheckGenericArgumentsResult::RequirementFailure: + if (loc.isValid()) { + TypeChecker::diagnoseRequirementFailure( + result.getRequirementFailureInfo(), loc, noteLoc, + decl->getDeclaredInterfaceType(), genericSig.getGenericParams(), + substitutions, module); + } + + return false; + case CheckGenericArgumentsResult::SubstitutionFailure: return false; - case RequirementCheckResult::Success: + case CheckGenericArgumentsResult::Success: return true; } llvm_unreachable("invalid requirement check type"); @@ -949,26 +953,32 @@ Type TypeResolution::applyUnboundGenericArguments( noteLoc = loc; auto genericSig = decl->getGenericSignature(); - auto result = TypeChecker::checkGenericArguments( - module, loc, noteLoc, - UnboundGenericType::get(decl, parentTy, getASTContext()), - genericSig.getGenericParams(), genericSig.getRequirements(), - [&](SubstitutableType *type) -> Type { - auto result = QueryTypeSubstitutionMap{subs}(type); - if (result->hasTypeParameter()) { - if (const auto contextSig = getGenericSignature()) { - auto *genericEnv = contextSig.getGenericEnvironment(); - return genericEnv->mapTypeIntoContext(result); - } - } - return result; - }); + const auto substitutions = [&](SubstitutableType *type) -> Type { + auto result = QueryTypeSubstitutionMap{subs}(type); + if (result->hasTypeParameter()) { + if (const auto contextSig = getGenericSignature()) { + auto *genericEnv = contextSig.getGenericEnvironment(); + return genericEnv->mapTypeIntoContext(result); + } + } + return result; + }; + const auto result = TypeChecker::checkGenericArgumentsForDiagnostics( + module, genericSig.getRequirements(), substitutions); switch (result) { - case RequirementCheckResult::Failure: - case RequirementCheckResult::SubstitutionFailure: + case CheckGenericArgumentsResult::RequirementFailure: + if (loc.isValid()) { + TypeChecker::diagnoseRequirementFailure( + result.getRequirementFailureInfo(), loc, noteLoc, + UnboundGenericType::get(decl, parentTy, getASTContext()), + genericSig.getGenericParams(), substitutions, module); + } + + LLVM_FALLTHROUGH; + case CheckGenericArgumentsResult::SubstitutionFailure: return ErrorType::get(getASTContext()); - case RequirementCheckResult::Success: + case CheckGenericArgumentsResult::Success: break; } } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index b81ce52d22096..346f5fef5d3f1 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -209,9 +209,54 @@ struct ParentConditionalConformance { ArrayRef conformances); }; -/// The result of `checkGenericRequirement`. -enum class RequirementCheckResult { - Success, Failure, SubstitutionFailure +class CheckGenericArgumentsResult { +public: + enum Kind { Success, RequirementFailure, SubstitutionFailure }; + + struct RequirementFailureInfo { + /// The failed requirement. + Requirement Req; + + /// The failed requirement with substitutions applied. + Requirement SubstReq; + + /// The chain of conditional conformances that leads to the failed + /// requirement \c Req. Accordingly, \c Req is a conditional requirement of + /// the last conformance in the chain (if any). + SmallVector ReqPath; + }; + +private: + Kind Knd; + Optional ReqFailureInfo; + + CheckGenericArgumentsResult(Kind Knd, + Optional ReqFailureInfo) + : Knd(Knd), ReqFailureInfo(ReqFailureInfo) {} + +public: + static CheckGenericArgumentsResult createSuccess() { + return CheckGenericArgumentsResult(Success, None); + } + + static CheckGenericArgumentsResult createSubstitutionFailure() { + return CheckGenericArgumentsResult(SubstitutionFailure, None); + } + + static CheckGenericArgumentsResult createRequirementFailure( + Requirement Req, Requirement SubstReq, + SmallVector ReqPath) { + return CheckGenericArgumentsResult( + RequirementFailure, RequirementFailureInfo{Req, SubstReq, ReqPath}); + } + + const RequirementFailureInfo &getRequirementFailureInfo() const { + assert(Knd == RequirementFailure); + + return ReqFailureInfo.getValue(); + } + + operator Kind() const { return Knd; } }; /// Describes the kind of checked cast operation being performed. @@ -446,45 +491,36 @@ void checkProtocolSelfRequirements(ValueDecl *decl); /// declaration's type, otherwise we have no way to infer them. void checkReferencedGenericParams(GenericContext *dc); -/// Create a text string that describes the bindings of generic parameters -/// that are relevant to the given set of types, e.g., -/// "[with T = Bar, U = Wibble]". -/// -/// \param types The types that will be scanned for generic type parameters, -/// which will be used in the resulting type. -/// -/// \param genericParams The generic parameters to use to resugar any -/// generic parameters that occur within the types. -/// -/// \param substitutions The generic parameter -> generic argument -/// substitutions that will have been applied to these types. -/// These are used to produce the "parameter = argument" bindings in the test. -std::string gatherGenericParamBindingsText( - ArrayRef types, TypeArrayView genericParams, - TypeSubstitutionFn substitutions); - -/// Check the given set of generic arguments against the requirements in a -/// generic signature. -/// -/// \param module The module to use for conformace lookup. -/// \param loc The location at which any diagnostics should be emitted. -/// \param noteLoc The location at which any notes will be printed. -/// \param owner The type that owns the generic signature. -/// \param genericParams The generic parameters being substituted. -/// \param requirements The requirements against which the generic arguments -/// should be checked. -/// \param substitutions Substitutions from interface types of the signature. -RequirementCheckResult checkGenericArguments( - ModuleDecl *module, SourceLoc loc, SourceLoc noteLoc, Type owner, +/// Diagnose a requirement failure. +/// +/// \param errorLoc The location at which an error shall be emitted. +/// \param noteLoc The location at which any notes shall be emitted. +/// \param targetTy The type whose generic arguments caused the requirement +/// failure. +/// \param genericParams The generic parameters that were substituted. +/// \param substitutions The substitutions that caused the requirement failure. +void diagnoseRequirementFailure( + const CheckGenericArgumentsResult::RequirementFailureInfo &reqFailureInfo, + SourceLoc errorLoc, SourceLoc noteLoc, Type targetTy, TypeArrayView genericParams, - ArrayRef requirements, TypeSubstitutionFn substitutions, - SubstOptions options = None); - -/// A lower-level version of the above without diagnostic emission. -RequirementCheckResult checkGenericArguments( - ModuleDecl *module, - ArrayRef requirements, - TypeSubstitutionFn substitutions); + TypeSubstitutionFn substitutions, ModuleDecl *module); + +/// Check the given generic parameter substitutions against the given +/// requirements and report on any requirement failures in detail for +/// diagnostic needs. +CheckGenericArgumentsResult +checkGenericArgumentsForDiagnostics(ModuleDecl *module, + ArrayRef requirements, + TypeSubstitutionFn substitutions); + +/// Check the given generic parameter substitutions against the given +/// requirements. Unlike \c checkGenericArgumentsForDiagnostics, this version +/// reports just the result of the check and doesn't provide additional +/// information on requirement failures that is warranted for diagnostics. +CheckGenericArgumentsResult::Kind +checkGenericArguments(ModuleDecl *module, ArrayRef requirements, + TypeSubstitutionFn substitutions, + SubstOptions options = None); /// Checks whether the generic requirements imposed on the nested type /// declaration \p decl (if present) are in agreement with the substitutions diff --git a/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift index 7f3c30dd60a92..1c930878747fe 100644 --- a/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift +++ b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift @@ -434,7 +434,7 @@ final class TangentVectorWB: DummyAdditiveArithmetic, Differentiable { } // expected-error @+3 {{'Differentiable' requires the types 'VectorSpaceTypeAlias.TangentVector' (aka 'TangentVectorWB') and 'TangentVectorWB.TangentVector' be equivalent}} // expected-note @+2 {{requirement specified as 'Self.TangentVector' == 'Self.TangentVector.TangentVector' [with Self = VectorSpaceTypeAlias]}} -// expected-error @+1 {{type 'VectorSpaceTypeAlias' does not conform to protocol 'Differentiable'}} +// expected-error @+1 2 {{type 'VectorSpaceTypeAlias' does not conform to protocol 'Differentiable'}} FIXME: Duplicate error final class VectorSpaceTypeAlias: DummyAdditiveArithmetic, Differentiable { var w: Float var b: Float diff --git a/test/Distributed/actor_protocols.swift b/test/Distributed/actor_protocols.swift index 9c0699b14768c..8a2481dd50ab5 100644 --- a/test/Distributed/actor_protocols.swift +++ b/test/Distributed/actor_protocols.swift @@ -43,6 +43,8 @@ distributed actor DA: DistributedActor { typealias ActorSystem = FakeActorSystem } +// FIXME: Ideally, we should only emit the tailored conformance error. +// expected-error@+1 {{type 'A2' does not conform to protocol 'DistributedActor'}} actor A2: DistributedActor { // expected-error@-1{{non-distributed actor type 'A2' cannot conform to the 'DistributedActor' protocol}} {{1-1=distributed }} // expected-error@-2{{'DistributedActor' requires the types 'ObjectIdentifier' and 'FakeActorSystem.ActorID' (aka 'ActorAddress') be equivalent}} @@ -63,6 +65,8 @@ actor A2: DistributedActor { } } +// FIXME: Ideally, we should only emit the tailored conformance error. +// expected-error@+1 {{type 'C2' does not conform to protocol 'DistributedActor'}} final class C2: DistributedActor { // expected-error@-1{{non-actor type 'C2' cannot conform to the 'Actor' protocol}} // expected-error@-2{{'DistributedActor' requires the types 'ObjectIdentifier' and 'FakeActorSystem.ActorID' (aka 'ActorAddress') be equivalent}} diff --git a/test/Generics/associated_type_where_clause.swift b/test/Generics/associated_type_where_clause.swift index 733872c9d956f..356cdf35a9632 100644 --- a/test/Generics/associated_type_where_clause.swift +++ b/test/Generics/associated_type_where_clause.swift @@ -39,7 +39,8 @@ struct ConcreteNestedConformsInfer: NestedConforms { func foo(_: ConcreteConforms) {} } struct BadConcreteNestedConforms: NestedConforms { - // expected-error@-1 {{type 'ConcreteConformsNonFoo2.T' (aka 'Float') does not conform to protocol 'Foo2'}} +// expected-error@-1 {{type 'BadConcreteNestedConforms' does not conform to protocol 'NestedConforms'}} +// expected-error@-2 {{type 'ConcreteConformsNonFoo2.T' (aka 'Float') does not conform to protocol 'Foo2'}} typealias U = ConcreteConformsNonFoo2 } struct BadConcreteNestedConformsInfer: NestedConforms { @@ -71,8 +72,10 @@ func needsNestedSameType(_: X.Type) { needsSameType(X.U.T.self, Int.self) } struct BadConcreteNestedSameType: NestedSameType { - // expected-error@-1 {{'NestedSameType' requires the types 'ConcreteConformsNonFoo2.T' (aka 'Float') and 'Int' be equivalent}} - // expected-note@-2 {{requirement specified as 'Self.U.T' == 'Int' [with Self = BadConcreteNestedSameType]}} +// expected-error@-1 {{type 'BadConcreteNestedSameType' does not conform to protocol 'NestedSameType'}} +// expected-error@-2 {{'NestedSameType' requires the types 'ConcreteConformsNonFoo2.T' (aka 'Float') and 'Int' be equivalent}} +// expected-note@-3 {{requirement specified as 'Self.U.T' == 'Int' [with Self = BadConcreteNestedSameType]}} + typealias U = ConcreteConformsNonFoo2 } struct BadConcreteNestedSameTypeInfer: NestedSameType { diff --git a/test/Generics/conditional_conformances.swift b/test/Generics/conditional_conformances.swift index 7aa6f7497ba1e..81842a40c32fa 100644 --- a/test/Generics/conditional_conformances.swift +++ b/test/Generics/conditional_conformances.swift @@ -229,10 +229,12 @@ func inheritequal_bad(_: U) { struct InheritLess {} extension InheritLess: P2 where T: P1 {} -extension InheritLess: P5 {} // expected-error{{type 'T' does not conform to protocol 'P1'}} -// expected-error@-1{{'P5' requires that 'T' conform to 'P1'}} -// expected-note@-2{{requirement specified as 'T' : 'P1'}} -// expected-note@-3{{requirement from conditional conformance of 'InheritLess' to 'P2'}} +extension InheritLess: P5 {} +// expected-error@-1 {{type 'InheritLess' does not conform to protocol 'P5'}} +// expected-error@-2 {{type 'T' does not conform to protocol 'P1'}} +// expected-error@-3 {{'P5' requires that 'T' conform to 'P1'}} +// expected-note@-4 {{requirement specified as 'T' : 'P1'}} +// expected-note@-5 {{requirement from conditional conformance of 'InheritLess' to 'P2'}} struct InheritMore {} diff --git a/test/Generics/protocol_where_clause.swift b/test/Generics/protocol_where_clause.swift index 3fc22f935f58a..33ea9320b9169 100644 --- a/test/Generics/protocol_where_clause.swift +++ b/test/Generics/protocol_where_clause.swift @@ -35,7 +35,8 @@ struct ConcreteConforms: Conforms { typealias T = Int } struct BadConcreteConforms: Conforms { - // expected-error@-1 {{type 'BadConcreteConforms.T' (aka 'String') does not conform to protocol 'Foo'}} +// expected-error@-1 {{type 'BadConcreteConforms' does not conform to protocol 'Conforms}} +// expected-error@-2 {{type 'BadConcreteConforms.T' (aka 'String') does not conform to protocol 'Foo'}} typealias T = String } @@ -47,8 +48,10 @@ struct ConcreteSameType: SameType { typealias T = Int typealias U = Int } -struct BadConcreteSameType: SameType { // expected-error{{'SameType' requires the types 'BadConcreteSameType.T' (aka 'Int') and 'BadConcreteSameType.U' (aka 'Float') be equivalent}} - // expected-note@-1{{requirement specified as 'Self.T' == 'Self.U' [with Self = BadConcreteSameType]}} +struct BadConcreteSameType: SameType { + // expected-error@-1 {{type 'BadConcreteSameType' does not conform to protocol 'SameType'}} + // expected-error@-2 {{'SameType' requires the types 'BadConcreteSameType.T' (aka 'Int') and 'BadConcreteSameType.U' (aka 'Float') be equivalent}} + // expected-note@-3 {{requirement specified as 'Self.T' == 'Self.U' [with Self = BadConcreteSameType]}} typealias T = Int typealias U = Float } @@ -63,7 +66,8 @@ struct ConcreteNestedConforms: NestedConforms { typealias U = ConcreteParent } struct BadConcreteNestedConforms: NestedConforms { - // expected-error@-1 {{type 'ConcreteParentNonFoo2.T' (aka 'Float') does not conform to protocol 'Foo2'}} +// expected-error@-1 {{type 'BadConcreteNestedConforms' does not conform to protocol 'NestedConforms'}} +// expected-error@-2 {{type 'ConcreteParentNonFoo2.T' (aka 'Float') does not conform to protocol 'Foo2'}} typealias U = ConcreteParentNonFoo2 } diff --git a/test/decl/protocol/conforms/failure.swift b/test/decl/protocol/conforms/failure.swift index d446790a7321d..c3f1809aee752 100644 --- a/test/decl/protocol/conforms/failure.swift +++ b/test/decl/protocol/conforms/failure.swift @@ -247,3 +247,17 @@ do { typealias A = Bool // expected-note {{possibly intended match 'Conformer.A' (aka 'Bool') does not conform to 'Sequence'}} } } + +class Class13 {} +protocol P13a { + associatedtype A +} +protocol P13b: P13a where A: Class13 {} +do { + struct Conformer: P13b { + // expected-error@-1 {{type 'Conformer' does not conform to protocol 'P13b'}} + // expected-error@-2 {{'P13b' requires that 'Conformer.A' (aka 'Array') inherit from 'Class13'}} + // expected-note@-3 {{requirement specified as 'Self.A' : 'Class13' [with Self = Conformer]}} + typealias A = Array + } +} diff --git a/test/decl/protocol/protocol_with_superclass.swift b/test/decl/protocol/protocol_with_superclass.swift index f297a6da9689f..9f1abe1bf95d7 100644 --- a/test/decl/protocol/protocol_with_superclass.swift +++ b/test/decl/protocol/protocol_with_superclass.swift @@ -95,8 +95,9 @@ func usesProtoRefinesClass2(_ t: T) { } class BadConformingClass1 : ProtoRefinesClass { - // expected-error@-1 {{'ProtoRefinesClass' requires that 'BadConformingClass1' inherit from 'Generic'}} - // expected-note@-2 {{requirement specified as 'Self' : 'Generic' [with Self = BadConformingClass1]}} + // expected-error@-1 {{type 'BadConformingClass1' does not conform to protocol 'ProtoRefinesClass'}} + // expected-error@-2 {{'ProtoRefinesClass' requires that 'BadConformingClass1' inherit from 'Generic'}} + // expected-note@-3 {{requirement specified as 'Self' : 'Generic' [with Self = BadConformingClass1]}} func requirementUsesClassTypes(_: ConcreteAlias, _: GenericAlias) { // expected-error@-1 {{cannot find type 'ConcreteAlias' in scope}} // expected-error@-2 {{cannot find type 'GenericAlias' in scope}} @@ -112,8 +113,9 @@ class BadConformingClass2 : Generic, ProtoRefinesClass { // expected-error@-1 {{'ProtoRefinesClass' requires that 'BadConformingClass2' inherit from 'Generic'}} // expected-note@-2 {{requirement specified as 'Self' : 'Generic' [with Self = BadConformingClass2]}} // expected-error@-3 {{type 'BadConformingClass2' does not conform to protocol 'ProtoRefinesClass'}} + + // expected-note@+1 {{candidate has non-matching type '(BadConformingClass2.ConcreteAlias, BadConformingClass2.GenericAlias) -> ()' (aka '(String, (String, String)) -> ()')}} func requirementUsesClassTypes(_: ConcreteAlias, _: GenericAlias) { - // expected-note@-1 {{candidate has non-matching type '(BadConformingClass2.ConcreteAlias, BadConformingClass2.GenericAlias) -> ()' (aka '(String, (String, String)) -> ()')}} _ = ConcreteAlias.self _ = GenericAlias.self } @@ -315,8 +317,9 @@ class SecondClass : FirstClass {} protocol SecondProtocol : SecondClass, FirstProtocol {} class FirstConformer : FirstClass, SecondProtocol {} -// expected-error@-1 {{'SecondProtocol' requires that 'FirstConformer' inherit from 'SecondClass'}} -// expected-note@-2 {{requirement specified as 'Self' : 'SecondClass' [with Self = FirstConformer]}} +// expected-error@-1 {{type 'FirstConformer' does not conform to protocol 'SecondProtocol'}} +// expected-error@-2 {{'SecondProtocol' requires that 'FirstConformer' inherit from 'SecondClass'}} +// expected-note@-3 {{requirement specified as 'Self' : 'SecondClass' [with Self = FirstConformer]}} class SecondConformer : SecondClass, SecondProtocol {} diff --git a/test/decl/protocol/protocol_with_superclass_where_clause.swift b/test/decl/protocol/protocol_with_superclass_where_clause.swift index 01c439e0468d4..edb4084f78521 100644 --- a/test/decl/protocol/protocol_with_superclass_where_clause.swift +++ b/test/decl/protocol/protocol_with_superclass_where_clause.swift @@ -96,8 +96,9 @@ func usesProtoRefinesClass2(_ t: T) { } class BadConformingClass1 : ProtoRefinesClass { - // expected-error@-1 {{'ProtoRefinesClass' requires that 'BadConformingClass1' inherit from 'Generic'}} - // expected-note@-2 {{requirement specified as 'Self' : 'Generic' [with Self = BadConformingClass1]}} + // expected-error@-1 {{type 'BadConformingClass1' does not conform to protocol 'ProtoRefinesClass'}} + // expected-error@-2 {{'ProtoRefinesClass' requires that 'BadConformingClass1' inherit from 'Generic'}} + // expected-note@-3 {{requirement specified as 'Self' : 'Generic' [with Self = BadConformingClass1]}} func requirementUsesClassTypes(_: ConcreteAlias, _: GenericAlias) { // expected-error@-1 {{cannot find type 'ConcreteAlias' in scope}} // expected-error@-2 {{cannot find type 'GenericAlias' in scope}} @@ -113,8 +114,9 @@ class BadConformingClass2 : Generic, ProtoRefinesClass { // expected-error@-1 {{'ProtoRefinesClass' requires that 'BadConformingClass2' inherit from 'Generic'}} // expected-note@-2 {{requirement specified as 'Self' : 'Generic' [with Self = BadConformingClass2]}} // expected-error@-3 {{type 'BadConformingClass2' does not conform to protocol 'ProtoRefinesClass'}} + + // expected-note@+1 {{candidate has non-matching type '(BadConformingClass2.ConcreteAlias, BadConformingClass2.GenericAlias) -> ()' (aka '(String, (String, String)) -> ()')}} func requirementUsesClassTypes(_: ConcreteAlias, _: GenericAlias) { - // expected-note@-1 {{candidate has non-matching type '(BadConformingClass2.ConcreteAlias, BadConformingClass2.GenericAlias) -> ()' (aka '(String, (String, String)) -> ()')}} _ = ConcreteAlias.self _ = GenericAlias.self } @@ -316,8 +318,9 @@ class SecondClass : FirstClass {} protocol SecondProtocol where Self : SecondClass, Self : FirstProtocol {} class FirstConformer : FirstClass, SecondProtocol {} -// expected-error@-1 {{'SecondProtocol' requires that 'FirstConformer' inherit from 'SecondClass'}} -// expected-note@-2 {{requirement specified as 'Self' : 'SecondClass' [with Self = FirstConformer]}} +// expected-error@-1 {{type 'FirstConformer' does not conform to protocol 'SecondProtocol'}} +// expected-error@-2 {{'SecondProtocol' requires that 'FirstConformer' inherit from 'SecondClass'}} +// expected-note@-3 {{requirement specified as 'Self' : 'SecondClass' [with Self = FirstConformer]}} class SecondConformer : SecondClass, SecondProtocol {} diff --git a/test/decl/protocol/req/associated_type_inference_fixed_type.swift b/test/decl/protocol/req/associated_type_inference_fixed_type.swift index 439a42dcbee60..f64178e2af0be 100644 --- a/test/decl/protocol/req/associated_type_inference_fixed_type.swift +++ b/test/decl/protocol/req/associated_type_inference_fixed_type.swift @@ -66,6 +66,7 @@ do { struct Conformer: P8a, P8b {} // expected-error@-1 {{'P8b' requires the types 'Conformer.A' (aka 'Never') and 'Bool' be equivalent}} // expected-note@-2 {{requirement specified as 'Self.A' == 'Bool' [with Self = Conformer]}} + // expected-error@-3 {{type 'Conformer' does not conform to protocol 'P8b'}} } protocol P9a where A == Never { @@ -75,6 +76,7 @@ protocol P9b: P9a { associatedtype A } struct S9a: P9b {} +// expected-error@+3 {{type 'S9b' does not conform to protocol 'P9a'}} // expected-error@+2 {{'P9a' requires the types 'S9b.A' (aka 'Bool') and 'Never' be equivalent}} // expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S9b]}} struct S9b: P9b { @@ -94,6 +96,7 @@ extension P10b { } // FIXME: 'P10 extension.A' should not be considered a viable type witness; // instead, the compiler should infer A := Never and synthesize S10.A. +// expected-error@+3 {{type 'S10' does not conform to protocol 'P10a'}} // expected-error@+2 {{'P10a' requires the types 'S10.A' (aka 'Bool') and 'Never' be equivalent}} // expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S10]}} struct S10: P10b, P10a {} @@ -323,13 +326,15 @@ do { struct Conformer1: Q28a {} // expected-error@-1 {{'P28b' requires the types 'Conformer1.A' (aka 'Int') and 'Bool' be equivalent}} // expected-note@-2 {{requirement specified as 'Self.A' == 'Bool' [with Self = Conformer1]}} + // expected-error@-3 {{type 'Conformer1' does not conform to protocol 'P28b'}} struct Conformer2: Q28b {} // expected-error@-1 {{'P28c' requires the types 'Conformer2.A' (aka 'Int') and 'Never' be equivalent}} // expected-error@-2 {{'P28b' requires the types 'Conformer2.A' (aka 'Int') and 'Bool' be equivalent}} // expected-note@-3 {{requirement specified as 'Self.A' == 'Never' [with Self = Conformer2]}} // expected-note@-4 {{requirement specified as 'Self.A' == 'Bool' [with Self = Conformer2]}} - + // expected-error@-5 {{type 'Conformer2' does not conform to protocol 'P28b'}} + // expected-error@-6 {{type 'Conformer2' does not conform to protocol 'P28c'}} } protocol P29a where A == Int { @@ -353,6 +358,7 @@ do { struct Conformer1: Q29a {} // expected-error@-1 {{'P29b' requires the types 'Conformer1.B' (aka 'Int') and 'Never' be equivalent}} // expected-note@-2 {{requirement specified as 'Self.B' == 'Never' [with Self = Conformer1]}} + // expected-error@-3 {{type 'Conformer1' does not conform to protocol 'P29b'}} struct Conformer2: Q29b {} diff --git a/test/decl/protocol/req/associated_type_inference_fixed_type_experimental_inference.swift b/test/decl/protocol/req/associated_type_inference_fixed_type_experimental_inference.swift index 7b3795b1bb3bb..aca0ed9591d68 100644 --- a/test/decl/protocol/req/associated_type_inference_fixed_type_experimental_inference.swift +++ b/test/decl/protocol/req/associated_type_inference_fixed_type_experimental_inference.swift @@ -106,6 +106,7 @@ protocol P9b: P9a { // CHECK-NEXT: A => Never, // CHECK-NEXT: } struct S9a: P9b {} +// expected-error@+3 {{type 'S9b' does not conform to protocol 'P9a'}} // expected-error@+2 {{'P9a' requires the types 'S9b.A' (aka 'Bool') and 'Never' be equivalent}} // expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S9b]}} struct S9b: P9b { @@ -125,6 +126,7 @@ extension P10b { } // FIXME: 'P10 extension.A' should not be considered a viable type witness; // instead, the compiler should infer A := Never and synthesize S10.A. +// expected-error@+3 {{type 'S10' does not conform to protocol 'P10a'}} // expected-error@+2 {{'P10a' requires the types 'S10.A' (aka 'Bool') and 'Never' be equivalent}} // expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S10]}} struct S10: P10b, P10a {} diff --git a/test/decl/protocol/special/DistributedActor.swift b/test/decl/protocol/special/DistributedActor.swift index 986abc8abb749..b884128559899 100644 --- a/test/decl/protocol/special/DistributedActor.swift +++ b/test/decl/protocol/special/DistributedActor.swift @@ -43,8 +43,8 @@ distributed actor D4 { // expected-error@-6{{type 'D4' does not conform to protocol 'Encodable'}} let actorSystem: String - // expected-error@-1{{invalid redeclaration of synthesized property 'actorSystem'}} - // expected-error@-2{{property 'actorSystem' cannot be defined explicitly, as it conflicts with distributed actor synthesized stored property}} + // expected-error@-1{{property 'actorSystem' cannot be defined explicitly, as it conflicts with distributed actor synthesized stored property}} + // expected-error@-2 {{invalid redeclaration of synthesized property 'actorSystem'}} // expected-note@-3{{stored property 'actorSystem' without initial value prevents synthesized initializers}} let id: OtherActorIdentity // expected-error@-1{{property 'id' cannot be defined explicitly, as it conflicts with distributed actor synthesized stored property}}