THRIFT-3264 Fix Erlang 16 namespaced types
Client: Erlang
Patch: Nobuaki Sukegawa <nsukeg@gmail.com>

This closes #566
diff --git a/compiler/cpp/src/generate/t_erl_generator.cc b/compiler/cpp/src/generate/t_erl_generator.cc
index 8af5da2..c066636 100644
--- a/compiler/cpp/src/generate/t_erl_generator.cc
+++ b/compiler/cpp/src/generate/t_erl_generator.cc
@@ -56,6 +56,10 @@
 
     legacy_names_ = (parsed_options.find("legacynames") != parsed_options.end());
     maps_ = (parsed_options.find("maps") != parsed_options.end());
+    otp16_ = (parsed_options.find("otp16") != parsed_options.end());
+    if (maps_ && otp16_) {
+      throw "argument error: Cannot specify both maps and otp16; maps are not available for Erlang/OTP R16 or older";
+    }
   }
 
   /**
@@ -156,6 +160,9 @@
   /* if true use maps instead of dicts in generated code */
   bool maps_;
 
+  /* if true use non-namespaced dict and set instead of dict:dict and sets:set */
+  bool otp16_;
+
   /**
    * add function to export list
    */
@@ -527,11 +534,17 @@
   } else if (type->is_map()) {
     if (maps_) {
       return "#{}";
+    } else if (otp16_) {
+      return "dict()";
     } else {
       return "dict:dict()";
     }
   } else if (type->is_set()) {
-    return "sets:set()";
+    if (otp16_) {
+      return "set()";
+    } else {
+      return "sets:set()";
+    }
   } else if (type->is_list()) {
     return "list()";
   } else {
@@ -1027,4 +1040,5 @@
     erl,
     "Erlang",
     "    legacynames: Output files retain naming conventions of Thrift 0.9.1 and earlier.\n"
-    "    maps:        Generate maps instead of dicts.\n")
+    "    maps:        Generate maps instead of dicts.\n"
+    "    otp16:       Generate non-namespaced dict and set instead of dict:dict and sets:set.\n")
diff --git a/configure.ac b/configure.ac
index 9af7f65..0a3fd43 100755
--- a/configure.ac
+++ b/configure.ac
@@ -231,9 +231,16 @@
   fi
   if test -n "$ERL" -a -n "$ERLC" ; then
     have_erlang="yes"
+
+    # otp_release is simply a number (like "17") for OTP17+ while "R16..." for OTP16 or less.
+    # OTP version is currently only used for running tests.
+    if $ERL -eval 'erlang:display(erlang:system_info(otp_release)),halt().' -noshell | grep "^\"R" >/dev/null; then
+      erlang_otp16_or_less="yes"
+    fi
   fi
 fi
 AM_CONDITIONAL(WITH_ERLANG, [test "$have_erlang" = "yes"])
+AM_CONDITIONAL(ERLANG_OTP16, [test "$erlang_otp16_or_less" = "yes"])
 
 AX_THRIFT_LIB(nodejs, [Nodejs], yes)
 have_nodejs=no
diff --git a/lib/erl/Makefile.am b/lib/erl/Makefile.am
index 1f65a24..f48ff0a 100644
--- a/lib/erl/Makefile.am
+++ b/lib/erl/Makefile.am
@@ -21,12 +21,19 @@
 THRIFT_FILES = $(wildcard test/*.thrift) \
 		  ../../test/ThriftTest.thrift
 
-.generated: $(THRIFT_FILES)
+if ERLANG_OTP16
+.generated: $(THRIFT) $(THRIFT_FILES)
 	for f in $(THRIFT_FILES) ; do \
-	  $(THRIFT) --gen erl -o test $$f ; \
+		$(THRIFT) --gen erl:otp16 -o test $$f ; \
+	done ;
+else
+.generated: $(THRIFT) $(THRIFT_FILES)
+	for f in $(THRIFT_FILES) ; do \
+		$(THRIFT) --gen erl -o test $$f ; \
 	done ; \
 	$(THRIFT) --gen erl:maps -o test test/Thrift3214.thrift ; \
 	touch .generated
+endif
 
 all: .generated
 	./rebar get-deps
diff --git a/lib/erl/rebar.config b/lib/erl/rebar.config
index 0f5d40e..1ea18a4 100644
--- a/lib/erl/rebar.config
+++ b/lib/erl/rebar.config
@@ -1 +1 @@
-{erl_opts, [debug_info]}.
+{erl_opts, [{platform_define, "^R.*", otp16_or_less}, debug_info]}.
diff --git a/lib/erl/test/test_thrift_3214.erl b/lib/erl/test/test_thrift_3214.erl
index 118e779..0f9544b 100644
--- a/lib/erl/test/test_thrift_3214.erl
+++ b/lib/erl/test/test_thrift_3214.erl
@@ -23,6 +23,7 @@
 -include("gen-erl/thrift3214_types.hrl").
 
 -ifdef(TEST).
+-ifndef(otp16_or_less).
 -include_lib("eunit/include/eunit.hrl").
 
 record_generation_test_() ->
@@ -56,3 +57,4 @@
   ].
 
 -endif.
+-endif.