Home | History | Annotate | Download | only in meta
      1 /*
      2  * Copyright 2014 Google Inc. All rights reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef FRUIT_META_COMPONENT_H
     18 #define FRUIT_META_COMPONENT_H
     19 
     20 #include <fruit/fruit_forward_decls.h>
     21 #include <fruit/impl/fruit_internal_forward_decls.h>
     22 #include <fruit/impl/injection_debug_errors.h>
     23 #include <fruit/impl/meta/algos.h>
     24 #include <fruit/impl/meta/errors.h>
     25 #include <fruit/impl/meta/list.h>
     26 #include <fruit/impl/meta/map.h>
     27 #include <fruit/impl/meta/metaprogramming.h>
     28 #include <fruit/impl/meta/numeric_operations.h>
     29 #include <fruit/impl/meta/proof_trees.h>
     30 #include <fruit/impl/meta/set.h>
     31 #include <fruit/impl/meta/signatures.h>
     32 #include <fruit/impl/meta/wrappers.h>
     33 
     34 #include <memory>
     35 #include <type_traits>
     36 
     37 namespace fruit {
     38 namespace impl {
     39 namespace meta {
     40 
     41 //********************************************************************************************************************************
     42 // Part 1: Simple type functors (no ConsComp involved).
     43 //********************************************************************************************************************************
     44 
     45 // Given a type T, returns the class that should be injected to ensure that T is provided at runtime (if any).
     46 struct GetClassForType {
     47   // General case, if none of the following apply.
     48   // When adding a specialization here, make sure that the ComponentStorage
     49   // can actually get<> the specified type when the class was registered.
     50   template <typename T>
     51   struct apply;
     52 
     53   template <typename T>
     54   struct apply<Type<T>> {
     55     using type = Type<T>;
     56   };
     57 
     58   template <typename T>
     59   struct apply<Type<const T>> {
     60     using type = Type<T>;
     61   };
     62 
     63   template <typename T>
     64   struct apply<Type<T*>> {
     65     using type = Type<T>;
     66   };
     67 
     68   template <typename T>
     69   struct apply<Type<T&>> {
     70     using type = Type<T>;
     71   };
     72 
     73   template <typename T>
     74   struct apply<Type<const T*>> {
     75     using type = Type<T>;
     76   };
     77 
     78   template <typename T>
     79   struct apply<Type<const T&>> {
     80     using type = Type<T>;
     81   };
     82 
     83   template <typename T>
     84   struct apply<Type<std::shared_ptr<T>>> {
     85     using type = Type<T>;
     86   };
     87 
     88   template <typename T>
     89   struct apply<Type<Assisted<T>>> {
     90     using type = None;
     91   };
     92 
     93   template <typename T>
     94   struct apply<Type<Provider<T>>> {
     95     using type = Type<T>;
     96   };
     97 
     98   template <typename T>
     99   struct apply<Type<Provider<const T>>> {
    100     using type = Type<T>;
    101   };
    102 
    103   template <typename Annotation, typename T>
    104   struct apply<Type<fruit::Annotated<Annotation, T>>> {
    105     using type = Type<T>;
    106   };
    107 };
    108 
    109 struct GetClassForTypeVector {
    110   template <typename V>
    111   struct apply {
    112     using type = TransformVector(V, GetClassForType);
    113   };
    114 };
    115 
    116 // Given a type T, returns the type in the injection graph that corresponds to T.
    117 struct NormalizeType {
    118   // When adding a specialization here, make sure that the ComponentStorage
    119   // can actually get<> the specified type when the class was registered.
    120   template <typename T>
    121   struct apply;
    122 
    123   template <typename T>
    124   struct apply<Type<T>> {
    125     using type = Type<T>;
    126   };
    127 
    128   template <typename T>
    129   struct apply<Type<const T>> {
    130     using type = Type<T>;
    131   };
    132 
    133   template <typename T>
    134   struct apply<Type<T*>> {
    135     using type = Type<T>;
    136   };
    137 
    138   template <typename T>
    139   struct apply<Type<T&>> {
    140     using type = Type<T>;
    141   };
    142 
    143   template <typename T>
    144   struct apply<Type<const T*>> {
    145     using type = Type<T>;
    146   };
    147 
    148   template <typename T>
    149   struct apply<Type<const T&>> {
    150     using type = Type<T>;
    151   };
    152 
    153   template <typename T>
    154   struct apply<Type<std::shared_ptr<T>>> {
    155     using type = Type<T>;
    156   };
    157 
    158   template <typename T>
    159   struct apply<Type<Assisted<T>>> {
    160     using type = None;
    161   };
    162 
    163   template <typename T>
    164   struct apply<Type<Provider<T>>> {
    165     using type = Type<T>;
    166   };
    167 
    168   template <typename T>
    169   struct apply<Type<Provider<const T>>> {
    170     using type = Type<T>;
    171   };
    172 
    173   template <typename Annotation, typename T>
    174   struct apply<Type<fruit::Annotated<Annotation, T>>> {
    175     using type = Type<fruit::Annotated<Annotation, UnwrapType<Eval<NormalizeType(Type<T>)>>>>;
    176   };
    177 };
    178 
    179 struct NormalizeUntilStable {
    180   template <typename T>
    181   struct apply {
    182     using type = If(IsSame(NormalizeType(T), T), T, NormalizeUntilStable(NormalizeType(T)));
    183   };
    184 };
    185 
    186 struct NormalizeTypeVector {
    187   template <typename V>
    188   struct apply {
    189     using type = TransformVector(V, NormalizeType);
    190   };
    191 };
    192 
    193 struct TypeInjectionRequiresNonConstBinding {
    194   template <typename T>
    195   struct apply;
    196 
    197   template <typename T>
    198   struct apply<Type<T>> {
    199     using type = Bool<false>;
    200   };
    201 
    202   template <typename T>
    203   struct apply<Type<const T>> {
    204     using type = Bool<false>;
    205   };
    206 
    207   template <typename T>
    208   struct apply<Type<T*>> {
    209     using type = Bool<true>;
    210   };
    211 
    212   template <typename T>
    213   struct apply<Type<T&>> {
    214     using type = Bool<true>;
    215   };
    216 
    217   template <typename T>
    218   struct apply<Type<const T*>> {
    219     using type = Bool<false>;
    220   };
    221 
    222   template <typename T>
    223   struct apply<Type<const T&>> {
    224     using type = Bool<false>;
    225   };
    226 
    227   template <typename T>
    228   struct apply<Type<std::shared_ptr<T>>> {
    229     using type = Bool<true>;
    230   };
    231 
    232   template <typename T>
    233   struct apply<Type<Assisted<T>>> {
    234     using type = Bool<false>;
    235   };
    236 
    237   template <typename T>
    238   struct apply<Type<Provider<T>>> {
    239     using type = Bool<true>;
    240   };
    241 
    242   template <typename T>
    243   struct apply<Type<Provider<const T>>> {
    244     using type = Bool<false>;
    245   };
    246 
    247   template <typename Annotation, typename T>
    248   struct apply<Type<fruit::Annotated<Annotation, T>>> {
    249     using type = TypeInjectionRequiresNonConstBinding(Type<T>);
    250   };
    251 };
    252 
    253 // Returns U wrapped in the same annotations in AnnotatedT (if any).
    254 struct CopyAnnotation {
    255   template <typename AnnotatedT, typename U>
    256   struct apply;
    257 
    258   template <typename T, typename U>
    259   struct apply {
    260     using type = U;
    261   };
    262 
    263   template <typename Annotation, typename T, typename U>
    264   struct apply<Type<fruit::Annotated<Annotation, T>>, Type<U>> {
    265     using type = Type<fruit::Annotated<Annotation, U>>;
    266   };
    267 };
    268 
    269 struct IsValidSignature {
    270   template <typename Signature>
    271   struct apply {
    272     using type = Bool<false>;
    273   };
    274 
    275   template <typename T, typename... Args>
    276   struct apply<Type<T(Args...)>> {
    277     using type = Bool<true>;
    278   };
    279 };
    280 
    281 // Removes the Annotation (if any) wrapping a type T.
    282 struct RemoveAnnotations {
    283   template <typename T>
    284   struct apply;
    285 
    286   template <typename T>
    287   struct apply<Type<T>> {
    288     using type = Type<T>;
    289   };
    290 
    291   template <typename Annotation, typename T>
    292   struct apply<Type<fruit::Annotated<Annotation, T>>> {
    293     using type = Type<T>;
    294   };
    295 };
    296 
    297 // Removes the Annotation(s) (if any) wrapping the types in AnnotatedSignature.
    298 struct RemoveAnnotationsFromSignature {
    299   template <typename AnnotatedSignature>
    300   struct apply {
    301     using type = ConstructError(NotASignatureErrorTag, AnnotatedSignature);
    302   };
    303 
    304   template <typename AnnotatedT, typename... AnnotatedArgs>
    305   struct apply<Type<AnnotatedT(AnnotatedArgs...)>> {
    306     using type = ConsSignature(RemoveAnnotations(Type<AnnotatedT>), Id<RemoveAnnotations(Type<AnnotatedArgs>)>...);
    307   };
    308 };
    309 
    310 // Removes the Annotation(s) (if any) wrapping the types in the Vector V.
    311 struct RemoveAnnotationsFromVector {
    312   template <typename V>
    313   struct apply {
    314     using type = TransformVector(V, RemoveAnnotations);
    315   };
    316 };
    317 
    318 // Maps T->T* in a possibly-annotated type.
    319 struct AddPointerInAnnotatedType {
    320   template <typename T>
    321   struct apply;
    322 
    323   template <typename T>
    324   struct apply<Type<T>> {
    325     using type = Type<T*>;
    326   };
    327 
    328   template <typename Annotation, typename T>
    329   struct apply<Type<fruit::Annotated<Annotation, T>>> {
    330     using type = Type<fruit::Annotated<Annotation, T*>>;
    331   };
    332 };
    333 
    334 // TODO: This also does UnlabelAssisted<>. Consider renaming and/or removing that logic (and
    335 // letting callers do the unlabeling when desired).
    336 struct RemoveNonAssisted {
    337   template <typename V>
    338   struct apply {
    339     struct Helper {
    340       // Non-assisted case
    341       template <typename CurrentResult, typename T>
    342       struct apply {
    343         using type = CurrentResult;
    344       };
    345 
    346       template <typename CurrentResult, typename T>
    347       struct apply<CurrentResult, Type<Assisted<T>>> {
    348         using type = PushBack(CurrentResult, Type<T>);
    349       };
    350     };
    351 
    352     using type = FoldVector(V, Helper, Vector<>);
    353   };
    354 };
    355 
    356 struct RemoveAssisted {
    357   template <typename V>
    358   struct apply {
    359     struct Helper {
    360       // Non-assisted case
    361       template <typename CurrentResult, typename T>
    362       struct apply {
    363         using type = PushBack(CurrentResult, T);
    364       };
    365 
    366       // Assisted case
    367       template <typename CurrentResult, typename T>
    368       struct apply<CurrentResult, Type<Assisted<T>>> {
    369         using type = CurrentResult;
    370       };
    371     };
    372 
    373     using type = FoldVector(V, Helper, Vector<>);
    374   };
    375 };
    376 
    377 struct UnlabelAssistedSingleType {
    378   template <typename T>
    379   struct apply;
    380 
    381   template <typename T>
    382   struct apply<Type<T>> {
    383     using type = Type<T>;
    384   };
    385 
    386   template <typename T>
    387   struct apply<Type<Assisted<T>>> {
    388     using type = Type<T>;
    389   };
    390 };
    391 
    392 struct UnlabelAssisted {
    393   template <typename V>
    394   struct apply {
    395     using type = TransformVector(V, UnlabelAssistedSingleType);
    396   };
    397 };
    398 
    399 struct RequiredLambdaArgsForAssistedFactory {
    400   template <typename AnnotatedSignature>
    401   struct apply {
    402     using type = RemoveAnnotationsFromVector(UnlabelAssisted(SignatureArgs(AnnotatedSignature)));
    403   };
    404 };
    405 
    406 struct RequiredLambdaSignatureForAssistedFactory {
    407   template <typename AnnotatedSignature>
    408   struct apply {
    409     using type = ConsSignatureWithVector(RemoveAnnotations(SignatureType(AnnotatedSignature)),
    410                                          RequiredLambdaArgsForAssistedFactory(AnnotatedSignature));
    411   };
    412 };
    413 
    414 struct InjectedFunctionArgsForAssistedFactory {
    415   template <typename AnnotatedSignature>
    416   struct apply {
    417     using type = RemoveNonAssisted(SignatureArgs(AnnotatedSignature));
    418   };
    419 };
    420 
    421 struct InjectedSignatureForAssistedFactory {
    422   template <typename AnnotatedSignature>
    423   struct apply {
    424     using type = ConsSignatureWithVector(RemoveAnnotations(SignatureType(AnnotatedSignature)),
    425                                          InjectedFunctionArgsForAssistedFactory(AnnotatedSignature));
    426   };
    427 };
    428 
    429 struct IsAssisted {
    430   template <typename T>
    431   struct apply {
    432     using type = Bool<false>;
    433   };
    434 
    435   template <typename T>
    436   struct apply<Type<Assisted<T>>> {
    437     using type = Bool<true>;
    438   };
    439 };
    440 
    441 struct NumAssisted {
    442   template <typename V>
    443   struct apply;
    444 
    445   template <typename... Types>
    446   struct apply<Vector<Types...>> {
    447     using type = SumAll(typename IsAssisted::apply<Types>::type...);
    448   };
    449 };
    450 
    451 // Counts the number of Assisted<> types in V before the given index.
    452 struct NumAssistedBefore {
    453   template <typename Index, typename V>
    454   struct apply;
    455 
    456   template <typename V>
    457   struct apply<Int<0>, V> {
    458     using type = Int<0>;
    459   };
    460 
    461   template <int n, typename V>
    462   struct apply<Int<n>, V> {
    463     using N = Int<n>;
    464     using type = Minus(NumAssisted(V), NumAssisted(VectorRemoveFirstN(V, N)));
    465   };
    466 };
    467 
    468 // Checks whether C is auto-injectable thanks to an Inject typedef.
    469 struct HasInjectAnnotation {
    470   template <typename C>
    471   struct apply;
    472 
    473   template <typename C>
    474   struct apply<Type<C>> {
    475     template <typename C1>
    476     static Bool<true> test(typename C1::Inject*);
    477 
    478     template <typename>
    479     static Bool<false> test(...);
    480 
    481     using type = decltype(test<C>(nullptr));
    482   };
    483 };
    484 
    485 struct DoGetInjectAnnotation {
    486   template <typename C>
    487   struct apply;
    488 
    489   template <typename C>
    490   struct apply<Type<C>> {
    491     using type = Type<typename C::Inject>;
    492   };
    493 };
    494 
    495 struct GetInjectAnnotation {
    496   template <typename AnnotatedC>
    497   struct apply {
    498     using C = RemoveAnnotations(AnnotatedC);
    499     using DecoratedS = DoGetInjectAnnotation(C);
    500     using SResult = SignatureType(DecoratedS);
    501     using AnnotatedSArgs = SignatureArgs(DecoratedS);
    502     using SArgs = RemoveAnnotationsFromVector(UnlabelAssisted(AnnotatedSArgs));
    503     // We replace the non-annotated return type with the potentially-annotated AnnotatedC.
    504     using AnnotatedDecoratedS = ConsSignatureWithVector(AnnotatedC, AnnotatedSArgs);
    505     using type = If(IsAbstract(C), ConstructError(CannotConstructAbstractClassErrorTag, C),
    506                     If(Not(IsValidSignature(DecoratedS)),
    507                        ConstructError(InjectTypedefNotASignatureErrorTag, C, DecoratedS),
    508                        If(Not(IsSame(SResult, RemoveAnnotations(SResult))),
    509                           ConstructError(InjectTypedefWithAnnotationErrorTag, C),
    510                           If(Not(IsSame(C, SResult)), ConstructError(InjectTypedefForWrongClassErrorTag, C, SResult),
    511                              If(Not(IsConstructibleWithVector(C, SArgs)),
    512                                 ConstructError(NoConstructorMatchingInjectSignatureErrorTag, C,
    513                                                ConsSignatureWithVector(SResult, SArgs)),
    514                                 AnnotatedDecoratedS)))));
    515   };
    516 };
    517 
    518 //********************************************************************************************************************************
    519 // Part 2: Type functors involving at least one ConsComp.
    520 //********************************************************************************************************************************
    521 
    522 template <typename RsSupersetParam, typename PsParam, typename NonConstRsPsParam,
    523 #if !FRUIT_NO_LOOP_CHECK
    524           typename DepsParam,
    525 #endif
    526           typename InterfaceBindingsParam, typename DeferredBindingFunctorsParam>
    527 struct Comp {
    528   // The actual set of requirements is SetDifference(RsSuperset, Ps)
    529   // We don't store Rs explicitly because we'd need to remove elements very often (and that's slow).
    530   using RsSuperset = RsSupersetParam;
    531 
    532   using Ps = PsParam;
    533   // This is a set of normalized types.
    534   // - If a type is in SetDifference(RsSuperset, Ps) and not here: it's required as const only
    535   // - If a type is in SetDifference(RsSuperset, Ps) and also here: it's required as non-const
    536   // - If a type is in Ps and not here: it's provided as const only
    537   // - If a type is in Ps and also here: it's provided as non-const
    538   using NonConstRsPs = NonConstRsPsParam;
    539 #if !FRUIT_NO_LOOP_CHECK
    540   using Deps = DepsParam;
    541 #endif
    542   using InterfaceBindings = InterfaceBindingsParam;
    543   using DeferredBindingFunctors = DeferredBindingFunctorsParam;
    544 
    545   // Invariants:
    546   // * all types appearing as arguments of Deps are in Rs
    547   // * all types in Ps are at the head of one (and only one) Dep.
    548   //   (note that the types in Rs can appear in deps any number of times, 0 is also ok)
    549   // * Deps is of the form Vector<Dep...> with each Dep of the form T(Args...) and where Vector<Args...> is a set (no
    550   // repetitions).
    551   // * Bindings is a proof tree forest, with injected classes as formulas.
    552   // * Each element X of the list DeferredBindingFunctors has:
    553   //   - a default-constructible X::apply<Comp> type
    554   //   - a void X::apply<Comp>::operator(ComponentStorage&)
    555   //   - an X::apply<Comp>::Result type
    556   // * Each element of NonConstRsPs is in RsSuperset or in Ps (or both)
    557 };
    558 
    559 // Using ConsComp instead of Comp<...> in a meta-expression allows the types to be evaluated.
    560 // See ConsVector for more details.
    561 struct ConsComp {
    562   template <typename RsSupersetParam, typename PsParam, typename NonConstRsPsParam,
    563 #if !FRUIT_NO_LOOP_CHECK
    564             typename DepsParam,
    565 #endif
    566             typename InterfaceBindingsParam, typename DeferredBindingFunctorsParam>
    567   struct apply {
    568     using type = Comp<RsSupersetParam, PsParam, NonConstRsPsParam,
    569 #if !FRUIT_NO_LOOP_CHECK
    570                       DepsParam,
    571 #endif
    572                       InterfaceBindingsParam, DeferredBindingFunctorsParam>;
    573   };
    574 };
    575 
    576 struct GetComponentDeps {
    577   template <typename Comp>
    578   struct apply {
    579     using type = typename Comp::Deps;
    580   };
    581 };
    582 
    583 struct GetComponentPs {
    584   template <typename Comp>
    585   struct apply {
    586     using type = typename Comp::Ps;
    587   };
    588 };
    589 
    590 struct GetComponentRsSuperset {
    591   template <typename Comp>
    592   struct apply {
    593     using type = typename Comp::RsSuperset;
    594   };
    595 };
    596 
    597 struct GetComponentNonConstRsPs {
    598   template <typename Comp>
    599   struct apply {
    600     using type = typename Comp::NonConstRsPs;
    601   };
    602 };
    603 
    604 struct IsInjectableBareType {
    605   template <typename T>
    606   struct apply;
    607 
    608   template <typename T>
    609   struct apply<Type<T>> {
    610     using type = Bool<std::is_arithmetic<T>::value || std::is_class<T>::value || std::is_enum<T>::value>;
    611   };
    612 
    613   template <typename Annotation, typename T>
    614   struct apply<Type<fruit::Annotated<Annotation, T>>> {
    615     using type = Bool<false>;
    616   };
    617 
    618   template <typename T>
    619   struct apply<Type<std::shared_ptr<T>>> {
    620     using type = Bool<false>;
    621   };
    622 };
    623 
    624 // Checks if T is a (non-annotated) injectable type.
    625 struct IsInjectableType {
    626   template <typename T>
    627   struct apply {
    628     using type = IsInjectableBareType(NormalizeType(T));
    629   };
    630 };
    631 
    632 // Checks that T is a (non-annotated) injectable type. If it isn't this returns an error, otherwise it returns None.
    633 struct CheckInjectableType {
    634   template <typename T>
    635   struct apply {
    636     using type = If(Not(IsInjectableType(T)), ConstructError(NonInjectableTypeErrorTag, T), None);
    637   };
    638 };
    639 
    640 // Checks that Types... are (non-annotated) injectable types. If they have an annotation or they are not injectable it
    641 // an appropriate error is returned.
    642 // Otherwise this returns None.
    643 struct CheckInjectableTypeVector {
    644   struct Helper {
    645     template <typename CurrentResult, typename T>
    646     struct apply {
    647       using type = PropagateError(CheckInjectableType(T), CurrentResult);
    648     };
    649   };
    650 
    651   template <typename V>
    652   struct apply {
    653     using type = FoldVector(V, Helper, None);
    654   };
    655 };
    656 
    657 // Checks that Types... are normalized and injectable types. If not it returns an appropriate error.
    658 // If they are all normalized types this returns Result.
    659 struct CheckNormalizedTypes {
    660   template <typename V>
    661   struct apply;
    662 
    663   template <typename... Types>
    664   struct apply<Vector<Type<Types>...>> {
    665     struct Helper {
    666       template <typename CurrentResult, typename T>
    667       struct apply {
    668         using NormalizedType = NormalizeType(T);
    669         using type = PropagateError(CheckInjectableType(RemoveAnnotations(NormalizeUntilStable(T))),
    670                                     If(Not(IsSame(NormalizeType(T), T)),
    671                                        ConstructError(NonClassTypeErrorTag, RemoveAnnotations(T),
    672                                                       RemoveAnnotations(NormalizeUntilStable(T))),
    673                                        CurrentResult));
    674       };
    675     };
    676 
    677     using type = Fold(Helper, None, Type<Types>...);
    678   };
    679 };
    680 
    681 // Checks that Types... are not annotated types. If they have an annotation it returns an appropriate error.
    682 // If none of them is annotated, this returns None.
    683 struct CheckNotAnnotatedTypes {
    684   template <typename V>
    685   struct apply;
    686 
    687   template <typename... Types>
    688   struct apply<Vector<Type<Types>...>> {
    689     struct Helper {
    690       template <typename CurrentResult, typename T>
    691       struct apply {
    692         using TypeWithoutAnnotations = RemoveAnnotations(T);
    693         using type = If(Not(IsSame(TypeWithoutAnnotations, T)),
    694                         ConstructError(AnnotatedTypeErrorTag, T, TypeWithoutAnnotations), CurrentResult);
    695       };
    696     };
    697 
    698     using type = Fold(Helper, None, Type<Types>...);
    699   };
    700 };
    701 
    702 // Check that there are no fruit::Required<> types in Component/NormalizedComponent's arguments.
    703 // If there aren't any, this returns None.
    704 struct CheckNoRequiredTypesInComponentArguments {
    705   template <typename V>
    706   struct apply;
    707 
    708   template <typename... Types>
    709   struct apply<Vector<Types...>> {
    710     using type = None;
    711   };
    712 
    713   template <typename T, typename... OtherTypes>
    714   struct apply<Vector<Type<T>, OtherTypes...>> {
    715     using type = CheckNoRequiredTypesInComponentArguments(Vector<OtherTypes...>);
    716   };
    717 
    718   template <typename... RequiredArgs, typename... OtherTypes>
    719   struct apply<Vector<Type<fruit::Required<RequiredArgs...>>, OtherTypes...>> {
    720     using type = ConstructError(RequiredTypesInComponentArgumentsErrorTag, Type<fruit::Required<RequiredArgs...>>);
    721   };
    722 };
    723 
    724 // Check that there are no fruit::Required<> types in Injector's arguments.
    725 // If there aren't any, this returns None.
    726 struct CheckNoRequiredTypesInInjectorArguments {
    727   template <typename... Types>
    728   struct apply {
    729     using type = None;
    730   };
    731 
    732   template <typename T, typename... Types>
    733   struct apply<T, Types...> {
    734     using type = CheckNoRequiredTypesInInjectorArguments(Types...);
    735   };
    736 
    737   template <typename... RequiredArgs, typename... Types>
    738   struct apply<Type<fruit::Required<RequiredArgs...>>, Types...> {
    739     using type = ConstructError(InjectorWithRequirementsErrorTag, Type<RequiredArgs>...);
    740   };
    741 };
    742 
    743 // Checks that there are no repetitions in Types. If there are, it returns an appropriate error.
    744 // If there are no repetitions it returns None.
    745 struct CheckNoRepeatedTypes {
    746   template <typename V>
    747   struct apply;
    748 
    749   template <typename... Types>
    750   struct apply<Vector<Types...>> {
    751     using type = If(HasDuplicates(Vector<Types...>), ConstructError(RepeatedTypesErrorTag, Types...), None);
    752   };
    753 };
    754 
    755 struct RemoveConstFromType {
    756   template <typename T>
    757   struct apply;
    758 
    759   template <typename T>
    760   struct apply<Type<T>> {
    761     using type = Type<T>;
    762   };
    763 
    764   template <typename T>
    765   struct apply<Type<const T>> {
    766     using type = Type<T>;
    767   };
    768 
    769   template <typename Annotation, typename T>
    770   struct apply<Type<fruit::Annotated<Annotation, T>>> {
    771     using type = Type<fruit::Annotated<Annotation, T>>;
    772   };
    773 
    774   template <typename Annotation, typename T>
    775   struct apply<Type<fruit::Annotated<Annotation, const T>>> {
    776     using type = Type<fruit::Annotated<Annotation, T>>;
    777   };
    778 };
    779 
    780 struct RemoveConstFromTypes {
    781   template <typename V>
    782   struct apply;
    783 
    784   template <typename... Types>
    785   struct apply<Vector<Types...>> {
    786     using type = ConsVector(Id<RemoveConstFromType(Types)>...);
    787   };
    788 };
    789 
    790 struct RemoveConstTypes {
    791   struct Helper {
    792     template <typename Acc, typename T>
    793     struct apply;
    794 
    795     template <typename... AccContent, typename T>
    796     struct apply<Vector<AccContent...>, Type<const T>> {
    797       using type = Vector<AccContent...>;
    798     };
    799 
    800     template <typename... AccContent, typename T>
    801     struct apply<Vector<AccContent...>, Type<T>> {
    802       using type = Vector<AccContent..., Type<T>>;
    803     };
    804 
    805     template <typename... AccContent, typename Annotation, typename T>
    806     struct apply<Vector<AccContent...>, Type<fruit::Annotated<Annotation, const T>>> {
    807       using type = Vector<AccContent...>;
    808     };
    809 
    810     template <typename... AccContent, typename Annotation, typename T>
    811     struct apply<Vector<AccContent...>, Type<fruit::Annotated<Annotation, T>>> {
    812       using type = Vector<AccContent..., Type<fruit::Annotated<Annotation, T>>>;
    813     };
    814   };
    815 
    816   template <typename V>
    817   struct apply {
    818     using type = FoldVector(V, Helper, Vector<>);
    819   };
    820 };
    821 
    822 // From a vector of injected types, this filters out the types that only require const bindings and then normalizes
    823 // the types in the result.
    824 struct NormalizedNonConstTypesIn {
    825   struct Helper {
    826     template <typename Acc, typename T>
    827     struct apply {
    828       using type = If(TypeInjectionRequiresNonConstBinding(T), PushBack(Acc, NormalizeType(T)), Acc);
    829     };
    830   };
    831 
    832   template <typename V>
    833   struct apply {
    834     using type = FoldVector(V, Helper, Vector<>);
    835   };
    836 };
    837 
    838 struct ConstructComponentImpl {
    839   // Non-specialized case: no requirements.
    840   template <typename... Ps>
    841   struct apply {
    842     using type = PropagateError(
    843         CheckNoRepeatedTypes(RemoveConstFromTypes(Vector<Ps...>)),
    844         PropagateError(CheckNormalizedTypes(RemoveConstFromTypes(Vector<Ps...>)),
    845                        PropagateError(CheckNoRequiredTypesInComponentArguments(Vector<Ps...>),
    846                                       ConsComp(EmptySet, VectorToSetUnchecked(RemoveConstFromTypes(Vector<Ps...>)),
    847                                                RemoveConstTypes(Vector<Ps...>),
    848 #if !FRUIT_NO_LOOP_CHECK
    849                                                Vector<Pair<Ps, Vector<>>...>,
    850 #endif
    851                                                Vector<>, EmptyList))));
    852   };
    853 
    854   // With requirements.
    855   template <typename... Rs, typename... Ps>
    856   struct apply<Type<Required<Rs...>>, Ps...> {
    857     using type1 = PropagateError(
    858         CheckNoRepeatedTypes(RemoveConstFromTypes(Vector<Type<Rs>..., Ps...>)),
    859         PropagateError(CheckNormalizedTypes(RemoveConstFromTypes(Vector<Type<Rs>..., Ps...>)),
    860                        PropagateError(CheckNoRequiredTypesInComponentArguments(Vector<Ps...>),
    861                                       ConsComp(VectorToSetUnchecked(RemoveConstFromTypes(Vector<Type<Rs>...>)),
    862                                                VectorToSetUnchecked(RemoveConstFromTypes(Vector<Ps...>)),
    863                                                RemoveConstTypes(Vector<Type<Rs>..., Ps...>),
    864 #if !FRUIT_NO_LOOP_CHECK
    865                                                Vector<Pair<Ps, Vector<Type<Rs>...>>...>,
    866 #endif
    867                                                Vector<>, EmptyList))));
    868 
    869 #if !FRUIT_NO_LOOP_CHECK && FRUIT_EXTRA_DEBUG
    870     using Loop = ProofForestFindLoop(GetComponentDeps(type1));
    871     using type = If(IsNone(Loop), type1, ConstructErrorWithArgVector(SelfLoopErrorTag, Loop));
    872 #else  // FRUIT_NO_LOOP_CHECK || !FRUIT_EXTRA_DEBUG
    873     using type = type1;
    874 #endif // FRUIT_NO_LOOP_CHECK || !FRUIT_EXTRA_DEBUG
    875   };
    876 };
    877 
    878 struct CheckTypesNotProvidedAsConst {
    879   template <typename Comp, typename V>
    880   struct apply {
    881     struct Helper {
    882       template <typename Acc, typename T>
    883       struct apply {
    884         using type = If(And(IsInSet(T, typename Comp::Ps), Not(IsInSet(T, typename Comp::NonConstRsPs))),
    885                         ConstructError(NonConstBindingRequiredButConstBindingProvidedErrorTag, T), Acc);
    886       };
    887     };
    888 
    889     using type = FoldVector(V, Helper, None);
    890   };
    891 };
    892 
    893 // Adds the types in NewRequirementsVector to the requirements (unless they are already provided/required).
    894 // The caller must convert the types to the corresponding class type and expand any Provider<>s.
    895 struct AddRequirements {
    896   template <typename Comp, typename NewRequirementsVector, typename NewNonConstRequirementsVector>
    897   struct apply {
    898     using Comp1 = ConsComp(FoldVector(NewRequirementsVector, AddToSet, typename Comp::RsSuperset), typename Comp::Ps,
    899                            FoldVector(NewNonConstRequirementsVector, AddToSet, typename Comp::NonConstRsPs),
    900 #if !FRUIT_NO_LOOP_CHECK
    901                            typename Comp::Deps,
    902 #endif
    903                            typename Comp::InterfaceBindings, typename Comp::DeferredBindingFunctors);
    904     using type = PropagateError(CheckTypesNotProvidedAsConst(Comp, NewNonConstRequirementsVector), Comp1);
    905   };
    906 };
    907 
    908 // Similar to AddProvidedType, but doesn't report an error if a Bind<C, CImpl> was present.
    909 struct AddProvidedTypeIgnoringInterfaceBindings {
    910   template <typename Comp, typename C, typename IsNonConst, typename CRequirements, typename CNonConstRequirements>
    911   struct apply {
    912     using Comp1 = ConsComp(
    913         FoldVector(CRequirements, AddToSet, typename Comp::RsSuperset), AddToSetUnchecked(typename Comp::Ps, C),
    914         If(IsNonConst, AddToSetUnchecked(FoldVector(CNonConstRequirements, AddToSet, typename Comp::NonConstRsPs), C),
    915            FoldVector(CNonConstRequirements, AddToSet, typename Comp::NonConstRsPs)),
    916 #if !FRUIT_NO_LOOP_CHECK
    917         PushFront(typename Comp::Deps, Pair<C, CRequirements>),
    918 #endif
    919         typename Comp::InterfaceBindings, typename Comp::DeferredBindingFunctors);
    920     using type = If(IsInSet(C, typename Comp::Ps), ConstructError(TypeAlreadyBoundErrorTag, C),
    921                     PropagateError(CheckTypesNotProvidedAsConst(Comp, CNonConstRequirements), Comp1));
    922   };
    923 };
    924 
    925 // Adds C to the provides and removes it from the requirements (if it was there at all).
    926 // Also checks that it wasn't already provided.
    927 // Moreover, adds the requirements of C to the requirements, unless they were already provided/required.
    928 // The caller must convert the types to the corresponding class type and expand any Provider<>s.
    929 struct AddProvidedType {
    930   template <typename Comp, typename C, typename IsNonConst, typename CRequirements, typename CNonConstRequirements>
    931   struct apply {
    932     using type = If(Not(IsNone(FindInMap(typename Comp::InterfaceBindings, C))),
    933                     ConstructError(TypeAlreadyBoundErrorTag, C),
    934                     AddProvidedTypeIgnoringInterfaceBindings(Comp, C, IsNonConst, CRequirements,
    935                                                              CNonConstRequirements));
    936   };
    937 };
    938 
    939 struct AddDeferredBinding {
    940   template <typename Comp, typename DeferredBinding>
    941   struct apply {
    942     using new_DeferredBindingFunctors = Cons<DeferredBinding, typename Comp::DeferredBindingFunctors>;
    943     using type = ConsComp(typename Comp::RsSuperset, typename Comp::Ps, typename Comp::NonConstRsPs,
    944 #if !FRUIT_NO_LOOP_CHECK
    945                           typename Comp::Deps,
    946 #endif
    947                           typename Comp::InterfaceBindings, new_DeferredBindingFunctors);
    948   };
    949 };
    950 
    951 struct CheckNoLoopInDeps {
    952   template <typename Comp>
    953   struct apply {
    954     using Loop = ProofForestFindLoop(typename Comp::Deps);
    955     using type = If(IsNone(Loop), Bool<true>, ConstructErrorWithArgVector(SelfLoopErrorTag, Loop));
    956   };
    957 };
    958 
    959 #if FRUIT_EXTRA_DEBUG || FRUIT_IN_META_TEST
    960 struct CheckComponentEntails {
    961   template <typename Comp, typename EntailedComp>
    962   struct apply {
    963     using CompRs = SetDifference(typename Comp::RsSuperset, typename Comp::Ps);
    964     using EntailedCompRs = SetDifference(typename EntailedComp::RsSuperset, typename EntailedComp::Ps);
    965     using CommonRs = SetIntersection(CompRs, EntailedCompRs);
    966     using CommonPs = SetIntersection(typename Comp::Ps, typename EntailedComp::Ps);
    967     using type =
    968         If(Not(IsContained(typename EntailedComp::Ps, typename Comp::Ps)),
    969            ConstructErrorWithArgVector(ComponentDoesNotEntailDueToProvidesErrorTag,
    970                                        SetToVector(SetDifference(typename EntailedComp::Ps, typename Comp::Ps))),
    971            If(Not(IsVectorContained(typename EntailedComp::InterfaceBindings, typename Comp::InterfaceBindings)),
    972               ConstructErrorWithArgVector(ComponentDoesNotEntailDueToInterfaceBindingsErrorTag,
    973                                           SetToVector(SetDifference(typename EntailedComp::InterfaceBindings,
    974                                                                     typename Comp::InterfaceBindings))),
    975               If(Not(IsContained(CompRs, EntailedCompRs)),
    976                  ConstructErrorWithArgVector(ComponentDoesNotEntailDueToRequirementsErrorTag,
    977                                              SetToVector(SetDifference(CompRs, EntailedCompRs))),
    978                  If(Not(IsContained(SetIntersection(CommonRs, typename Comp::NonConstRsPs),
    979                                     typename EntailedComp::NonConstRsPs)),
    980                     ConstructErrorWithArgVector(ComponentDoesNotEntailDueToDifferentConstnessOfRequirementsErrorTag,
    981                                                 SetToVector(SetDifference(SetIntersection(CommonRs,
    982                                                                                           typename Comp::NonConstRsPs),
    983                                                                           typename EntailedComp::NonConstRsPs))),
    984                     If(Not(IsContained(SetIntersection(CommonPs, typename EntailedComp::NonConstRsPs),
    985                                        typename Comp::NonConstRsPs)),
    986                        ConstructErrorWithArgVector(
    987                            ComponentDoesNotEntailDueToDifferentConstnessOfProvidesErrorTag,
    988                            SetToVector(SetDifference(SetIntersection(CommonPs, typename EntailedComp::NonConstRsPs),
    989                                                      typename Comp::NonConstRsPs))),
    990                        Bool<true>)))));
    991     static_assert(true || sizeof(typename CheckIfError<Eval<type>>::type), "");
    992   };
    993 };
    994 #endif // FRUIT_EXTRA_DEBUG || FRUIT_IN_META_TEST
    995 
    996 // This calls ConstructError(NoBindingFoundErrorTag, ...) or
    997 // ConstructError(NoBindingFoundForAbstractClassErrorTag, ...) as appropriate.
    998 // Call this when we're unable to auto-inject a type AnnotatedC and we're giving up.
    999 struct ConstructNoBindingFoundError {
   1000   template <typename AnnotatedC>
   1001   struct apply {
   1002     using type = If(IsAbstract(RemoveAnnotations(AnnotatedC)),
   1003                     ConstructError(NoBindingFoundForAbstractClassErrorTag, AnnotatedC, RemoveAnnotations(AnnotatedC)),
   1004                     ConstructError(NoBindingFoundErrorTag, AnnotatedC));
   1005   };
   1006 };
   1007 
   1008 } // namespace meta
   1009 } // namespace impl
   1010 } // namespace fruit
   1011 
   1012 #endif // FRUIT_META_COMPONENT_H
   1013