• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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