Support dynamic type (#323)

diff --git a/src/main/java/com/squareup/kotlinpoet/TypeName.kt b/src/main/java/com/squareup/kotlinpoet/TypeName.kt
index 440b550..dc38df5 100644
--- a/src/main/java/com/squareup/kotlinpoet/TypeName.kt
+++ b/src/main/java/com/squareup/kotlinpoet/TypeName.kt
@@ -217,6 +217,25 @@
 @JvmField val FLOAT = ClassName("kotlin", "Float")
 @JvmField val DOUBLE = ClassName("kotlin", "Double")
 
+@JvmField val DYNAMIC = object : TypeName(false, emptyList()) {
+
+  override fun asNullable() =
+      throw UnsupportedOperationException("dynamic can't be nullable")
+
+  override fun asNonNullable() =
+      throw UnsupportedOperationException("dynamic can't be non-nullable")
+
+  override fun annotated(annotations: List<AnnotationSpec>) =
+      throw UnsupportedOperationException("dynamic can't have annotations")
+
+  override fun withoutAnnotations() =
+      throw UnsupportedOperationException("dynamic can't have annotations")
+
+  override fun emit(out: CodeWriter) = out.apply {
+    emit("dynamic")
+  }
+}
+
 /** Returns a [TypeName] equivalent to this [TypeMirror]. */
 @JvmName("get")
 fun TypeMirror.asTypeName() = TypeName.get(this, mutableMapOf())
diff --git a/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt b/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
index 63ff13f..7e07421 100644
--- a/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
+++ b/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
@@ -603,4 +603,29 @@
       |}
       |""".trimMargin())
   }
+
+  @Test fun dynamicType() {
+    val source = FileSpec.builder(tacosPackage, "Taco")
+        .addFunction(FunSpec.builder("dynamicTest")
+            .addCode(CodeBlock.of("%L", PropertySpec.builder("d1", DYNAMIC)
+                .initializer("%S", "Taco")
+                .build()))
+            .addCode(CodeBlock.of("%L", PropertySpec.builder("d2", DYNAMIC)
+                .initializer("1f")
+                .build()))
+            .addStatement("// dynamics are dangerous!")
+            .addStatement("println(d1 - d2)")
+            .build())
+        .build()
+    assertThat(source.toString()).isEqualTo("""
+      |package com.squareup.tacos
+      |
+      |fun dynamicTest() {
+      |    val d1: dynamic = "Taco"
+      |    val d2: dynamic = 1f
+      |    // dynamics are dangerous!
+      |    println(d1 - d2)
+      |}
+      |""".trimMargin())
+  }
 }