presto-main/src/main/java/io/prestosql/sql/planner/optimizations/PropertyDerivations.java/PropertyDerivations/visitProject
class PropertyDerivations:        @Override
        public ActualProperties visitProject(ProjectNode node, List<ActualProperties> inputProperties)
        {
            ActualProperties properties = Iterables.getOnlyElement(inputProperties);

            Map<Symbol, Symbol> identities = computeIdentityTranslations(node.getAssignments().getMap());

            ActualProperties translatedProperties = properties.translate(column -> Optional.ofNullable(identities.get(column)), expression -> rewriteExpression(node.getAssignments().getMap(), expression));

            // Extract additional constants
            Map<Symbol, NullableValue> constants = new HashMap<>();
            for (Map.Entry<Symbol, Expression> assignment : node.getAssignments().entrySet()) {
                Expression expression = assignment.getValue();

                Map<NodeRef<Expression>, Type> expressionTypes = typeAnalyzer.getTypes(session, types, expression);
                Type type = requireNonNull(expressionTypes.get(NodeRef.of(expression)));
                ExpressionInterpreter optimizer = ExpressionInterpreter.expressionOptimizer(expression, metadata, session, expressionTypes);
                // TODO:
                // We want to use a symbol resolver that looks up in the constants from the input subplan
                // to take advantage of constant-folding for complex expressions
                // However, that currently causes errors when those expressions operate on arrays or row types
                // ("ROW comparison not supported for fields with null elements", etc)
                Object value = optimizer.optimize(NoOpSymbolResolver.INSTANCE);

                if (value instanceof SymbolReference) {
                    Symbol symbol = Symbol.from((SymbolReference) value);
                    NullableValue existingConstantValue = constants.get(symbol);
                    if (existingConstantValue != null) {
                        constants.put(assignment.getKey(), new NullableValue(type, value));
                    }
                }
                else if (!(value instanceof Expression)) {
                    constants.put(assignment.getKey(), new NullableValue(type, value));
                }
            }
            constants.putAll(translatedProperties.getConstants());

            return ActualProperties.builderFrom(translatedProperties)
                    .constants(constants)
                    .build();
        }