@@ -108,7 +108,6 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
108108 IGNORED_ATTR(StaticInitializeObjCMetadata)
109109 IGNORED_ATTR(SynthesizedProtocol)
110110 IGNORED_ATTR(Testable)
111- IGNORED_ATTR(TypeEraser)
112111 IGNORED_ATTR(WeakLinked)
113112 IGNORED_ATTR(PrivateImport)
114113 IGNORED_ATTR(DisfavoredOverload)
@@ -240,6 +239,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
240239
241240 void visitDiscardableResultAttr (DiscardableResultAttr *attr);
242241 void visitDynamicReplacementAttr (DynamicReplacementAttr *attr);
242+ void visitTypeEraserAttr (TypeEraserAttr *attr);
243243 void visitImplementsAttr (ImplementsAttr *attr);
244244
245245 void visitFrozenAttr (FrozenAttr *attr);
@@ -2390,6 +2390,179 @@ void AttributeChecker::visitDynamicReplacementAttr(DynamicReplacementAttr *attr)
23902390 }
23912391}
23922392
2393+ llvm::Expected<bool >
2394+ TypeEraserHasViableInitRequest::evaluate (Evaluator &evaluator,
2395+ TypeEraserAttr *attr,
2396+ ProtocolDecl *protocol) const {
2397+ auto &ctx = protocol->getASTContext ();
2398+ auto &diags = ctx.Diags ;
2399+ TypeLoc &typeEraserLoc = attr->getTypeEraserLoc ();
2400+ TypeRepr *typeEraserRepr = typeEraserLoc.getTypeRepr ();
2401+ DeclContext *dc = protocol->getDeclContext ();
2402+ Type protocolType = protocol->getDeclaredType ();
2403+
2404+ // Get the NominalTypeDecl for the type eraser.
2405+ Type typeEraser = typeEraserLoc.getType ();
2406+ if (!typeEraser && typeEraserRepr) {
2407+ auto resolution = TypeResolution::forContextual (protocol);
2408+ typeEraser = resolution.resolveType (typeEraserRepr, /* options=*/ None);
2409+ typeEraserLoc.setType (typeEraser);
2410+ }
2411+
2412+ if (typeEraser->hasError ())
2413+ return false ;
2414+
2415+ // The type eraser must be a concrete nominal type
2416+ auto nominalTypeDecl = typeEraser->getAnyNominal ();
2417+ if (auto typeAliasDecl = dyn_cast_or_null<TypeAliasDecl>(nominalTypeDecl))
2418+ nominalTypeDecl = typeAliasDecl->getUnderlyingType ()->getAnyNominal ();
2419+
2420+ if (!nominalTypeDecl || isa<ProtocolDecl>(nominalTypeDecl)) {
2421+ diags.diagnose (typeEraserLoc.getLoc (), diag::non_nominal_type_eraser);
2422+ return false ;
2423+ }
2424+
2425+ // The nominal type must be accessible wherever the protocol is accessible
2426+ if (nominalTypeDecl->getFormalAccess () < protocol->getFormalAccess ()) {
2427+ diags.diagnose (typeEraserLoc.getLoc (), diag::type_eraser_not_accessible,
2428+ nominalTypeDecl->getFormalAccess (), nominalTypeDecl->getName (),
2429+ protocolType, protocol->getFormalAccess ());
2430+ diags.diagnose (nominalTypeDecl->getLoc (), diag::type_eraser_declared_here);
2431+ return false ;
2432+ }
2433+
2434+ // The type eraser must conform to the annotated protocol
2435+ if (!TypeChecker::conformsToProtocol (typeEraser, protocol, dc, None)) {
2436+ diags.diagnose (typeEraserLoc.getLoc (), diag::type_eraser_does_not_conform,
2437+ typeEraser, protocolType);
2438+ diags.diagnose (nominalTypeDecl->getLoc (), diag::type_eraser_declared_here);
2439+ return false ;
2440+ }
2441+
2442+ // The type eraser must have an init of the form init<T: Protocol>(erasing: T)
2443+ auto lookupResult = TypeChecker::lookupMember (dc, typeEraser,
2444+ DeclNameRef::createConstructor ());
2445+
2446+ // Keep track of unviable init candidates for diagnostics
2447+ enum class UnviableReason {
2448+ Failable,
2449+ UnsatisfiedRequirements,
2450+ Inaccessible,
2451+ };
2452+ SmallVector<std::tuple<ConstructorDecl *, UnviableReason, Type>, 2 > unviable;
2453+
2454+ bool foundMatch = llvm::any_of (lookupResult, [&](const LookupResultEntry &entry) {
2455+ auto *init = cast<ConstructorDecl>(entry.getValueDecl ());
2456+ if (!init->isGeneric () || init->getGenericParams ()->size () != 1 )
2457+ return false ;
2458+
2459+ auto genericSignature = init->getGenericSignature ();
2460+ auto genericParamType = genericSignature->getInnermostGenericParams ().front ();
2461+
2462+ // Fow now, only allow one parameter.
2463+ auto params = init->getParameters ();
2464+ if (params->size () != 1 )
2465+ return false ;
2466+
2467+ // The parameter must have the form `erasing: T` where T conforms to the protocol.
2468+ ParamDecl *param = *init->getParameters ()->begin ();
2469+ if (param->getArgumentName () != ctx.Id_erasing ||
2470+ !param->getInterfaceType ()->isEqual (genericParamType) ||
2471+ !genericSignature->conformsToProtocol (genericParamType, protocol))
2472+ return false ;
2473+
2474+ // Allow other constraints as long as the init can be called with any
2475+ // type conforming to the annotated protocol. We will check this by
2476+ // substituting the protocol's Self type for the generic arg and check that
2477+ // the requirements in the generic signature are satisfied.
2478+ auto baseMap =
2479+ typeEraser->getContextSubstitutionMap (nominalTypeDecl->getParentModule (),
2480+ nominalTypeDecl);
2481+ QuerySubstitutionMap getSubstitution{baseMap};
2482+ auto subMap = SubstitutionMap::get (
2483+ genericSignature,
2484+ [&](SubstitutableType *type) -> Type {
2485+ if (type->isEqual (genericParamType))
2486+ return protocol->getSelfTypeInContext ();
2487+
2488+ return getSubstitution (type);
2489+ },
2490+ TypeChecker::LookUpConformance (dc));
2491+
2492+ // Use invalid 'SourceLoc's to suppress diagnostics.
2493+ auto result = TypeChecker::checkGenericArguments (
2494+ protocol, SourceLoc (), SourceLoc (), typeEraser,
2495+ genericSignature->getGenericParams (),
2496+ genericSignature->getRequirements (),
2497+ QuerySubstitutionMap{subMap},
2498+ TypeChecker::LookUpConformance (dc),
2499+ None);
2500+
2501+ if (result != RequirementCheckResult::Success) {
2502+ unviable.push_back (
2503+ std::make_tuple (init, UnviableReason::UnsatisfiedRequirements,
2504+ genericParamType));
2505+ return false ;
2506+ }
2507+
2508+ if (init->isFailable ()) {
2509+ unviable.push_back (
2510+ std::make_tuple (init, UnviableReason::Failable, genericParamType));
2511+ return false ;
2512+ }
2513+
2514+ if (init->getFormalAccess () < protocol->getFormalAccess ()) {
2515+ unviable.push_back (
2516+ std::make_tuple (init, UnviableReason::Inaccessible, genericParamType));
2517+ return false ;
2518+ }
2519+
2520+ return true ;
2521+ });
2522+
2523+ if (!foundMatch) {
2524+ if (unviable.empty ()) {
2525+ diags.diagnose (attr->getLocation (), diag::type_eraser_missing_init,
2526+ typeEraser, protocol->getName ().str ());
2527+ diags.diagnose (nominalTypeDecl->getLoc (), diag::type_eraser_declared_here);
2528+ return false ;
2529+ }
2530+
2531+ diags.diagnose (attr->getLocation (), diag::type_eraser_unviable_init,
2532+ typeEraser, protocol->getName ().str ());
2533+ for (auto &candidate: unviable) {
2534+ auto init = std::get<0 >(candidate);
2535+ auto reason = std::get<1 >(candidate);
2536+ auto genericParamType = std::get<2 >(candidate);
2537+
2538+ switch (reason) {
2539+ case UnviableReason::Failable:
2540+ diags.diagnose (init->getLoc (), diag::type_eraser_failable_init);
2541+ break ;
2542+ case UnviableReason::UnsatisfiedRequirements:
2543+ diags.diagnose (init->getLoc (),
2544+ diag::type_eraser_init_unsatisfied_requirements,
2545+ genericParamType, protocol->getName ().str ());
2546+ break ;
2547+ case UnviableReason::Inaccessible:
2548+ diags.diagnose (init->getLoc (), diag::type_eraser_init_not_accessible,
2549+ init->getFormalAccess (), protocolType,
2550+ protocol->getFormalAccess ());
2551+ break ;
2552+ }
2553+ }
2554+ return false ;
2555+ }
2556+
2557+ return true ;
2558+ }
2559+
2560+ void AttributeChecker::visitTypeEraserAttr (TypeEraserAttr *attr) {
2561+ assert (isa<ProtocolDecl>(D));
2562+ // Invoke the request.
2563+ (void )attr->hasViableTypeEraserInit (cast<ProtocolDecl>(D));
2564+ }
2565+
23932566void AttributeChecker::visitImplementsAttr (ImplementsAttr *attr) {
23942567 TypeLoc &ProtoTypeLoc = attr->getProtocolType ();
23952568
0 commit comments