@@ -101,11 +101,16 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
101101
102102 specs.forEach (_addTypesForRendererSpec);
103103
104+ var builtRenderers = < ClassElement > {};
105+
104106 while (_typesToProcess.isNotEmpty) {
105107 var info = _typesToProcess.removeFirst ();
106108
107109 if (info.isFullRenderer) {
108- _buildRenderer (info);
110+ var buildOnlyPublicFunction =
111+ builtRenderers.contains (info._contextClass);
112+ _buildRenderer (info, buildOnlyPublicFunction: buildOnlyPublicFunction);
113+ builtRenderers.add (info._contextClass);
109114 }
110115 }
111116
@@ -142,6 +147,18 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
142147 if (property.isPrivate || property.isStatic || property.isSetter) return ;
143148 if (property.hasProtected || property.hasVisibleForTesting) return ;
144149 var type = property.type.returnType;
150+ if (type is TypeParameterType ) {
151+ var bound = (type as TypeParameterType ).bound;
152+ if (bound == null || bound.isDynamic) {
153+ // Don't add functions for a generic type, for example
154+ // `List<E>.first` has type `E`, which we don't have a specific
155+ // renderer for.
156+ // TODO(srawlins): Find a solution for this. We can track all of the
157+ // concrete types substituted for `E` for example.
158+ return ;
159+ }
160+ type = bound;
161+ }
145162 var isFullRenderer = _isVisibleToMustache (type.element);
146163
147164 if (_typeSystem.isAssignableTo (type, _typeProvider.iterableDynamicType)) {
@@ -170,9 +187,8 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
170187
171188 /// Adds [type] to the [_typesToProcess] queue, if it is not already there.
172189 void _addTypeToProcess (ClassElement element, {@required isFullRenderer}) {
173- var typeToProcess = _typesToProcess
174- .singleWhere ((rs) => rs._contextClass == element, orElse: () => null );
175- if (typeToProcess == null ) {
190+ var types = _typesToProcess.where ((rs) => rs._contextClass == element);
191+ if (types.isEmpty) {
176192 var rendererInfo = _RendererInfo (element,
177193 isFullRenderer: isFullRenderer, public: _rendererClassesArePublic);
178194 _typesToProcess.add (rendererInfo);
@@ -181,11 +197,14 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
181197 _typeToRendererClassName[element] = rendererInfo._rendererClassName;
182198 }
183199 } else {
184- if (isFullRenderer && ! typeToProcess.isFullRenderer) {
185- // This is the only case in which we update a type-to-render.
186- typeToProcess.isFullRenderer = true ;
187- _typeToRenderFunctionName[element] = typeToProcess._renderFunctionName;
188- _typeToRendererClassName[element] = typeToProcess._rendererClassName;
200+ for (var typeToProcess in types) {
201+ if (isFullRenderer && ! typeToProcess.isFullRenderer) {
202+ // This is the only case in which we update a type-to-render.
203+ typeToProcess.isFullRenderer = true ;
204+ _typeToRenderFunctionName[element] =
205+ typeToProcess._renderFunctionName;
206+ _typeToRendererClassName[element] = typeToProcess._rendererClassName;
207+ }
189208 }
190209 }
191210 }
@@ -201,14 +220,19 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
201220 return _isVisibleToMustache (element.supertype.element);
202221 }
203222
204- /// Builds both the render function and the renderer class for [renderer] .
223+ /// Builds render functions and the renderer class for [renderer] .
205224 ///
206225 /// The function and the class are each written as Dart code to [_buffer] .
207226 ///
208227 /// If [renderer] also specifies a `publicApiFunctionName` , then a public API
209228 /// function (which renders a context object using a template file at a path,
210229 /// rather than an AST) is also written.
211- void _buildRenderer (_RendererInfo renderer) {
230+ ///
231+ /// If [buildOnlyPublicFunction] is true, then the private render function and
232+ /// renderer classes are not built, having been built for a different
233+ /// [_RendererInfo] .
234+ void _buildRenderer (_RendererInfo renderer,
235+ {@required bool buildOnlyPublicFunction}) {
212236 var typeName = renderer._typeName;
213237 var typeWithVariables = '$typeName ${renderer ._typeVariablesString }' ;
214238
@@ -221,6 +245,8 @@ String ${renderer.publicApiFunctionName}${renderer._typeParametersString}(
221245''' );
222246 }
223247
248+ if (buildOnlyPublicFunction) return ;
249+
224250 // Write out the render function.
225251 _buffer.writeln ('''
226252String ${renderer ._renderFunctionName }${renderer ._typeParametersString }(
0 commit comments