Trees.ValueDeclaration inferType(
        Trees.ValueDeclaration declaration,
        Trees.Expression expression,
        InferencePurpose inferenceKind) {

      if (expression instanceof BoundAccessExpression) {
        BoundAccessExpression scopeBoundAccess = (BoundAccessExpression) expression;
        Accessors.BoundAccess lastAccess = Iterables.getLast(asBoundAccess(scopeBoundAccess.accessor()));

        if (inferenceKind == InferencePurpose.ITERATE) {
          if (!lastAccess.isContainer()) {
            throw new TypingException(String.format("Not iterable type '%s'%n\tin expression '%s'",
                lastAccess.type,
                scopeBoundAccess.path()));
          }
        }

        if (declaration.type().isPresent()) {
          return declaration.withType(resolveDeclared(declaration.type().get(), declaration.name()))
              .withContainedType(ResolvedType.of(resolveType(declaration.type().get(), false)));
        }

        if (inferenceKind == InferencePurpose.ITERATE) {
          TypeMirror resolved = lastAccess.containedType;
          return declaration.withType(declare(resolved, declaration.name()))
              .withContainedType(ResolvedType.of(resolved));
        } else if (inferenceKind == InferencePurpose.COLLECT) {
          TypeMirror resolved = knife.accessors.wrapIterable(lastAccess.type);
          return declaration.withType(declare(resolved, declaration.name()))
              .withContainedType(ResolvedType.of(lastAccess.type));
        } else {
          return declaration.withType(declare(lastAccess.type, declaration.name()))
              .withContainedType(ResolvedType.of(lastAccess.type));
        }
      }

      if (declaration.type().isPresent()) {
        return declaration.withType(resolveDeclared(declaration.type().get(), declaration.name()))
            .withContainedType(ResolvedType.of(resolveType(declaration.type().get(), false)));
      }

      throw new TypingException(String.format("Value should be typed %s%n\texpression '%s'",
          declaration.name(),
          expression));
    }
Declare template or invokable. There's no {{@code isDeclared} check because we potentially
might allow to define several templates with the same name but different types of arguments,
to be resolved at runtime. (akin to multimethods). Might need to check if the same
combination of parameters was already used.
@param name identifier
@return resolved type
generator-processor/src/org/immutables/generator/processor/TypeResolver.java