protected IRExpression compile_impl() {
    ISymbol symbol = _expr().getSymbol();

    ICompilableType gsClass = getGosuClass();
    if ((Keyword.KW_this.equals(symbol.getName()) || Keyword.KW_super.equals(symbol.getName()))
        &&
        // 'this' must be an external symbol when in a program e.g., studio debugger expression
        (!(gsClass instanceof IGosuProgram) || gsClass.isAnonymous())) {
      if (_cc().isBlockInvoke() && _cc().currentlyCompilingBlock()) {
        while (gsClass instanceof IBlockClass) {
          gsClass = gsClass.getEnclosingType();
        }
        return pushOuter(gsClass);
      } else {
        return pushThis();
      }
    } else if (symbol instanceof DynamicPropertySymbol
        && ((DynamicPropertySymbol) symbol).getGetterDfs() instanceof OuterFunctionSymbol) {
      // 'outer'
      return pushOuterForOuterSymbol();
    } else {
      return pushSymbolValue(symbol);
    }
  }
  public IRExpression pushSymbolValue(ISymbol symbol) {
    IType type = symbol.getType();
    Class symClass;
    IReducedSymbol reducedSym;
    if (symbol instanceof ReducedSymbol.SyntheticSymbol) {
      reducedSym = ((ReducedSymbol.SyntheticSymbol) symbol).getReducedSymbol();
      symClass = reducedSym.getSymbolClass();
    } else {
      reducedSym = symbol;
      symClass = symbol.getClass();
    }
    if (_cc().isExternalSymbol(reducedSym.getName())) {
      // unbox( symbols.getValue( name ) )
      return unboxValueToType(
          reducedSym.getType(),
          callMethod(
              IExternalSymbolMap.class,
              "getValue",
              new Class[] {String.class, int.class},
              pushExternalSymbolsMap(),
              Arrays.asList(
                  pushConstant(reducedSym.getName()), pushConstant(getArrayDims(reducedSym)))));
    } else if (DynamicSymbol.class.isAssignableFrom(symClass)) {
      // Instance or Static field

      IRProperty irProp = IRPropertyFactory.createIRProperty(reducedSym);
      if (!irProp.isStatic()) {
        if (isMemberOnEnclosingType(reducedSym) != null) {
          // Instance field from 'outer'
          return getField_new(
              irProp, pushOuter(reducedSym.getGosuClass()), getDescriptor(reducedSym.getType()));
        } else {
          // Instance field from 'this'
          return getField_new(irProp, pushThis(), getDescriptor(reducedSym.getType()));
        }
      } else {
        // Static field
        return getField_new(irProp, null, getDescriptor(reducedSym.getType()));
      }
    } else if (CapturedSymbol.class.isAssignableFrom(symClass)) {
      // Captured symbol is stored as a Field on an anonymous inner class (one elem array of
      // symbol's type)
      // e.g., val$myFiield[0] = value. Note a captured symbol is duplicated in all nested classes.
      IRProperty irProp = IRPropertyFactory.createIRProperty(getGosuClass(), reducedSym);
      return getField_new(irProp, pushThis(), getDescriptor(reducedSym.getType()));
    } else if (reducedSym.getIndex() >= 0) {
      // Local var

      if (reducedSym.isValueBoxed()) {
        // Local var is captured in an anonymous inner class.
        // Symbol's value maintained as a one elem array of symbol's type.
        return buildArrayLoad(
            identifier(_cc().getSymbol(reducedSym.getName())), 0, getDescriptor(type));
      } else {
        // Simple local var
        return identifier(_cc().getSymbol(reducedSym.getName()));
      }
    } else if (DynamicPropertySymbol.class.isAssignableFrom(symClass)) {
      IRProperty irProp;
      if (reducedSym instanceof DynamicPropertySymbol) {
        irProp = IRPropertyFactory.createIRProperty((DynamicPropertySymbol) reducedSym);
      } else {
        irProp = IRPropertyFactory.createIRProperty((ReducedDynamicPropertySymbol) reducedSym);
      }

      IRExpression root;
      if (irProp.isStatic()) {
        root = null;
      } else {
        ICompilableType targetType = isMemberOnEnclosingType(reducedSym);
        if (targetType != null) {
          root = pushOuter(targetType);
        } else {
          root = pushThis();
        }
      }
      IRExpression getterCall =
          callMethod(irProp.getGetterMethod(), root, Collections.<IRExpression>emptyList());
      return castResultingTypeIfNecessary(
          getDescriptor(reducedSym.getType()), irProp.getType(), getterCall);
    } else {
      throw new UnsupportedOperationException(
          "Don't know how to compile symbol: "
              + reducedSym.getClass().getSimpleName()
              + ": "
              + reducedSym.getName()
              + ": "
              + reducedSym.getType());
    }
  }