Compile dot and not expressions to byte code.

--
MOS_MIGRATED_REVID=107378197
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/DotExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/DotExpression.java
index e8482a7..84805e9 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/DotExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/DotExpression.java
@@ -16,7 +16,15 @@
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.syntax.FuncallExpression.MethodDescriptor;
+import com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils;
+import com.google.devtools.build.lib.syntax.compiler.DebugInfo;
+import com.google.devtools.build.lib.syntax.compiler.VariableScope;
 
+import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
+import net.bytebuddy.implementation.bytecode.Duplication;
+import net.bytebuddy.implementation.bytecode.constant.TextConstant;
+
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -52,14 +60,22 @@
     Object objValue = obj.eval(env);
     String name = field.getName();
     Object result = eval(objValue, name, getLocation(), env);
+    return checkResult(objValue, result, name, getLocation());
+  }
+
+  /**
+   * Throws the correct error message if the result is null depending on the objValue.
+   */
+  public static Object checkResult(Object objValue, Object result, String name, Location loc)
+    throws EvalException {
     if (result == null) {
       if (objValue instanceof ClassObject) {
         String customErrorMessage = ((ClassObject) objValue).errorMessage(name);
         if (customErrorMessage != null) {
-          throw new EvalException(getLocation(), customErrorMessage);
+          throw new EvalException(loc, customErrorMessage);
         }
       }
-      throw new EvalException(getLocation(), Printer.format("Object of type '%s' has no field %r",
+      throw new EvalException(loc, Printer.format("Object of type '%s' has no field %r",
               EvalUtils.getDataTypeName(objValue), name));
     }
     return result;
@@ -96,6 +112,7 @@
         return FuncallExpression.callMethod(method, name, objValue, new Object[] {}, loc, env);
       }
     }
+
     return null;
   }
 
@@ -108,4 +125,26 @@
   void validate(ValidationEnvironment env) throws EvalException {
     obj.validate(env);
   }
+
+  @Override
+  ByteCodeAppender compile(VariableScope scope, DebugInfo debugInfo) throws EvalException {
+    List<ByteCodeAppender> code = new ArrayList<>();
+    code.add(obj.compile(scope, debugInfo));
+    TextConstant name = new TextConstant(field.getName());
+    ByteCodeUtils.append(
+        code,
+        Duplication.SINGLE,
+        name,
+        debugInfo.add(this).loadLocation,
+        scope.loadEnvironment(),
+        ByteCodeUtils.invoke(DotExpression.class, "eval", Object.class, String.class,
+            Location.class, Environment.class),
+        // at this point we have the value of obj and the result of eval on the stack
+        name,
+        debugInfo.add(this).loadLocation,
+        ByteCodeUtils.invoke(DotExpression.class, "checkResult", Object.class, Object.class,
+            String.class, Location.class)
+        );
+    return ByteCodeUtils.compoundAppender(code);
+  }
 }