diff --git a/.gitignore b/.gitignore
index 0ed3a9bc00b783501a6eea5b322c7b2e914d038f..ff664eac0e1e96201aba7422f2e35c26f30f171b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 build
 .*.sw[po]
+.sw[po]
 *~
 *.pyc
 *.pyo
diff --git a/doc/reference.rst b/doc/reference.rst
index 83883dce5975171a91a357176bf305422bd3b7aa..1f19611d1df126967c8cdcf766c125c464bda2a9 100644
--- a/doc/reference.rst
+++ b/doc/reference.rst
@@ -50,6 +50,9 @@ optional.
 * `<float32>` declares `lhs` as a temporary variable, with shape given
   by the ranges of the `lhs` subscripts. (Note that in this case, the
   `lhs` subscripts must be pure inames, not expressions, for now.)
+  Instead of a concrete type, an empty set of angle brackets `<>` may be
+  given to indicate that type inference should figure out the type of the
+  temporary.
 
 * `[i,j|k,l]` specifies the inames within which this instruction is run.
   Independent copies of the inames `k` and `l` will be made for this
diff --git a/loopy/__init__.py b/loopy/__init__.py
index 3c72b50e431ca8e4d1ebe1a11a6664adcd346dea..d23cc67076a26581ebbe33eabe2a75ed46fa69f7 100644
--- a/loopy/__init__.py
+++ b/loopy/__init__.py
@@ -46,6 +46,9 @@ __all__ = ["ScalarArg", "ArrayArg", "ConstantArrayArg", "ImageArg", "LoopKernel"
         "precompute", "add_prefetch"
         ]
 
+class infer_type:
+    pass
+
 # }}}
 
 # {{{ dimension split
diff --git a/loopy/codegen/expression.py b/loopy/codegen/expression.py
index 7a32ac76256158209e9c4834b7366cffaf642756..fc28f1d7662a8db3914131550950f2a1a4f0b19d 100644
--- a/loopy/codegen/expression.py
+++ b/loopy/codegen/expression.py
@@ -8,6 +8,9 @@ from pymbolic.mapper import CombineMapper
 
 # {{{ type inference
 
+class TypeInferenceFailure(RuntimeError):
+    pass
+
 class TypeInferenceMapper(CombineMapper):
     def __init__(self, kernel, temporary_variables=None):
         self.kernel = kernel
@@ -33,7 +36,7 @@ class TypeInferenceMapper(CombineMapper):
                 pass
             else:
                 if not result is other:
-                    raise TypeError("nothing known about result of operation on "
+                    raise TypeInferenceFailure("nothing known about result of operation on "
                             "'%s' and '%s'" % (result, other))
 
         return result
@@ -60,14 +63,20 @@ class TypeInferenceMapper(CombineMapper):
             pass
 
         try:
-            return self.temporary_variables[expr.name].dtype
+            result = self.temporary_variables[expr.name].dtype
         except KeyError:
             pass
+        else:
+            from loopy import infer_type
+            if result is infer_type:
+                raise TypeInferenceFailure("attempted type inference on "
+                        "variable requiring type inference")
+            return result
 
         if expr.name in self.kernel.all_inames():
             return np.dtype(np.int16) # don't force single-precision upcast
 
-        raise RuntimeError("type inference: nothing known about '%s'" % expr.name)
+        raise TypeInferenceFailure("nothing known about '%s'" % expr.name)
 
     def map_lookup(self, expr):
         agg_result = self.rec(expr.aggregate)
diff --git a/loopy/creation.py b/loopy/creation.py
index 40df171be4787d123e406238724d0c2f84d18b3a..71806998f22d063d4a6d4ab3380084e6483998ce 100644
--- a/loopy/creation.py
+++ b/loopy/creation.py
@@ -96,6 +96,9 @@ def create_temporaries(knl):
     new_insns = []
     new_temp_vars = knl.temporary_variables.copy()
 
+    from loopy.codegen.expression import TypeInferenceMapper
+    tim = TypeInferenceMapper(knl, new_temp_vars)
+
     for insn in knl.instructions:
         from loopy.kernel import (
                 find_var_base_indices_and_shape_from_inames,
@@ -104,6 +107,13 @@ def create_temporaries(knl):
         if insn.temp_var_type is not None:
             assignee_name = insn.get_assignee_var_name()
 
+            temp_var_type = insn.temp_var_type
+            from loopy import infer_type
+            if temp_var_type is infer_type:
+                # FIXME dependencies among type-inferred variables
+                # are not allowed yet.
+                temp_var_type = tim(insn.expression)
+
             assignee_indices = []
             from pymbolic.primitives import Variable
             for index_expr in insn.get_assignee_indices():
@@ -123,7 +133,7 @@ def create_temporaries(knl):
 
             new_temp_vars[assignee_name] = TemporaryVariable(
                     name=assignee_name,
-                    dtype=np.dtype(insn.temp_var_type),
+                    dtype=temp_var_type,
                     is_local=None,
                     base_indices=base_indices,
                     shape=shape)
diff --git a/loopy/kernel.py b/loopy/kernel.py
index 034e7b05541ae54e02a46223a118c8fd741b7daa..76ffe4ed41208e785fd034eb2c209cc6697d275f 100644
--- a/loopy/kernel.py
+++ b/loopy/kernel.py
@@ -293,6 +293,12 @@ class Instruction(Record):
             boostable_into=None,
             temp_var_type=None, duplicate_inames_and_tags=[]):
 
+        from loopy.symbolic import parse
+        if isinstance(assignee, str):
+            assignee = parse(assignee)
+        if isinstance(expression, str):
+            assignee = parse(expression)
+
         assert isinstance(forced_iname_deps, set)
         assert isinstance(insn_deps, set)
 
@@ -557,7 +563,7 @@ class LoopKernel(Record):
                     "(?P<iname_deps_and_tags>[\s\w,:.]*)"
                     "(?:\|(?P<duplicate_inames_and_tags>[\s\w,:.]*))?"
                 "\])?"
-                "\s*(?:\<(?P<temp_var_type>.+?)\>)?"
+                "\s*(?:\<(?P<temp_var_type>.*?)\>)?"
                 "\s*(?P<lhs>.+?)\s*(?<!\:)=\s*(?P<rhs>.+?)"
                 "\s*?(?:\:\s*(?P<insn_deps>[\s\w,]+))?$"
                 )
@@ -648,7 +654,11 @@ class LoopKernel(Record):
                     duplicate_inames_and_tags = []
 
                 if groups["temp_var_type"] is not None:
-                    temp_var_type = groups["temp_var_type"]
+                    if groups["temp_var_type"]:
+                        temp_var_type = np.dtype(groups["temp_var_type"])
+                    else:
+                        from loopy import infer_type
+                        temp_var_type = infer_type
                 else:
                     temp_var_type = None