code: private static <T extends QueryNode> NodeCentricOptimizationResults<T> propagateSubstitution(
              IntermediateQuery query,
              Optional<ImmutableSubstitution<VariableOrGroundTerm>> optionalSubstitution,
              T topNode) throws EmptyQueryException {
          if (optionalSubstitution.isPresent()) {
  
              // TODO: filter the non-bound variables from the substitution before propagating!!!
  
              SubstitutionPropagationProposal<T> propagationProposal = new SubstitutionPropagationProposalImpl<>(
                      topNode, optionalSubstitution.get(), false);
  
              // Forces the use of an internal executor (the treeComponent must remain the same).
              return query.applyProposal(propagationProposal, true);
          }
          /*
           * No substitution to propagate
           */
          else {
              return new NodeCentricOptimizationResultsImpl<>(query, topNode);
          }
  
      }
docs: Applies the substitution from the topNode.
  
  NB: the topNode can be a JoinLikeNode, a replacing FilterNode or the replacing child