diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,27 @@
 # Revision history for hpython
 
+## 0.2
+
+* Improved Plated instance for exprs
+
+  It now drills down into collections, parameters, arguments, subscripts, and
+  comprehensions
+  
+* Added `_Idents` traversal
+
+* Annotations are now wrapped in the `Ann` type to aid generic deriving
+
+* Added `HasExprs` instance for `Module`
+
+* Added `HasStatements` instance for `Statement`
+
+* Added IO-based `read-` functions to `Language.Python.Parse`
+
+* Re-export `Data.Validation` from `Language.Python.Parse`
+
+* Added `annot` and `annot_` lenses to `Language.Python.Syntax.Ann` to retrieve
+  annotations from structures
+
 ## 0.1.0.1
 
 *2019-01-07*
diff --git a/example/Main.hs b/example/Main.hs
--- a/example/Main.hs
+++ b/example/Main.hs
@@ -7,6 +7,7 @@
 import FixMutableDefaultArguments
 import OptimizeTailRecursion
 import Indentation
+import Recase
 import Validation
 
 import Language.Python.Render (showModule)
@@ -46,4 +47,8 @@
 
   section $ do
     putStrLn "Validated\n"
-    doValidating
+  doValidating
+
+  section $ do
+    putStrLn "Recased\n"
+  recase
diff --git a/example/Programs.hs b/example/Programs.hs
--- a/example/Programs.hs
+++ b/example/Programs.hs
@@ -22,26 +22,26 @@
 append_to :: Raw Statement
 append_to =
   CompoundStatement $
-  Fundef () [] (Indents [] ())
+  Fundef (Ann ()) [] (Indents [] (Ann ()))
     Nothing
     (Space :| [])
     "append_to"
     []
-    ( CommaSepMany (PositionalParam () "element" Nothing) (MkComma [Space]) $
-      CommaSepOne (KeywordParam () "to" Nothing [] (List () [] Nothing []))
+    ( CommaSepMany (PositionalParam (Ann ()) "element" Nothing) (MkComma [Space]) $
+      CommaSepOne (KeywordParam (Ann ()) "to" Nothing [] (List (Ann ()) [] Nothing []))
     )
     []
     Nothing
-    (SuiteMany () (MkColon []) Nothing LF $
+    (SuiteMany (Ann ()) (MkColon []) Nothing LF $
      Block []
      ( SmallStatement
-         (Indents [replicate 4 Space ^. from indentWhitespaces] ())
+         (Indents [replicate 4 Space ^. from indentWhitespaces] (Ann ()))
          (MkSmallStatement
-          (Expr () $
-           Call ()
-             (Deref () (Ident "to") [] "append")
+          (Expr (Ann ()) $
+           Call (Ann ())
+             (Deref (Ann ()) (Ident (Ann ()) "to") [] "append")
              []
-             (Just $ CommaSepOne1' (PositionalArg () (Ident "element")) Nothing)
+             (Just $ CommaSepOne1' (PositionalArg (Ann ()) (Ident (Ann ()) "element")) Nothing)
              [])
           []
           Nothing
@@ -50,9 +50,9 @@
      )
      [ Right $
          SmallStatement
-           (Indents [replicate 4 Space ^. from indentWhitespaces] ())
+           (Indents [replicate 4 Space ^. from indentWhitespaces] (Ann ()))
            (MkSmallStatement
-            (Return () [Space] (Just $ Ident "to"))
+            (Return (Ann ()) [Space] (Just $ Ident (Ann ()) "to"))
             []
             Nothing
             Nothing
diff --git a/example/Recase.hs b/example/Recase.hs
new file mode 100644
--- /dev/null
+++ b/example/Recase.hs
@@ -0,0 +1,29 @@
+{-# language TypeApplications #-}
+module Recase (recase) where
+
+import Control.Lens.Setter (over)
+import Control.Lens.Plated (transform)
+import Data.Char (toUpper)
+
+import qualified Data.Text.IO as Text
+
+import Language.Python.Parse
+import Language.Python.Optics.Idents
+import Language.Python.Render (showModule)
+import Language.Python.Syntax (identValue)
+
+snakeToCamel :: String -> String
+snakeToCamel =
+  transform $
+  \s -> case s of
+    '_' : c : cs -> toUpper c : cs
+    _ -> s
+
+recase :: IO ()
+recase = do
+  m <- readModule @(ParseError SrcInfo) "example/snake_cased.py"
+  case m of
+    Failure err -> error $ show err
+    Success a -> do
+      let fixed = over (_Idents.identValue) snakeToCamel a
+      Text.putStrLn $ showModule fixed
diff --git a/hpython.cabal b/hpython.cabal
--- a/hpython.cabal
+++ b/hpython.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                hpython
-version:             0.1.0.1
+version:             0.2
 synopsis:            Python language tools
 description:
   `hpython` provides an abstract syntax tree for Python 3.5, along with a parser,
@@ -35,6 +35,10 @@
                      test/files/indent_optics_out.py
                      test/files/indent_optics_in2.py
                      test/files/indent_optics_out2.py
+                     test/files/exprs_optics_in1.py
+                     test/files/exprs_optics_out1.py
+                     test/files/idents_optics_in1.py
+                     test/files/idents_optics_out1.py
                      test/files/joblib.py
                      test/files/joblib2.py
                      test/files/mypy.py
@@ -83,6 +87,7 @@
                      , Language.Python.Internal.Token
                      , Language.Python.Internal.Syntax.IR
                      , Language.Python.Optics
+                     , Language.Python.Optics.Idents
                      , Language.Python.Optics.Indents
                      , Language.Python.Optics.Newlines
                      , Language.Python.Optics.Validated
@@ -90,6 +95,7 @@
                      , Language.Python.Parse.Error
                      , Language.Python.Render
                      , Language.Python.Syntax
+                     , Language.Python.Syntax.Ann
                      , Language.Python.Syntax.AugAssign
                      , Language.Python.Syntax.CommaSep
                      , Language.Python.Syntax.Comment
@@ -124,6 +130,7 @@
                      , parsers >= 0.10 && < 0.13
                      , megaparsec >=6.3 && <7
                      , fingertree >=0.1 && <0.2
+                     , generic-lens >=1.0 && <1.2
                      , mtl >= 2.1 && < 2.3
                      , containers >=0.5.7.1 && <0.7
                      , deriving-compat >=0.4 && <0.6
@@ -148,6 +155,7 @@
                      , FixMutableDefaultArguments
                      , OptimizeTailRecursion
                      , Programs
+                     , Recase
                      , Validation
   hs-source-dirs:      example
   build-depends:       base >=4.9 && <5, lens, hpython, text
@@ -157,7 +165,6 @@
                        -Wunused-imports
   if flag(development)
     ghc-options:       -Werror
-
 
 benchmark bench
   main-is:             Main.hs
diff --git a/src/Language/Python/DSL.hs b/src/Language/Python/DSL.hs
--- a/src/Language/Python/DSL.hs
+++ b/src/Language/Python/DSL.hs
@@ -425,6 +425,7 @@
 import Data.Semigroup ((<>))
 
 import Language.Python.Optics
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.AugAssign
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Expr
@@ -473,7 +474,7 @@
 
 -- | Create a blank 'Line'
 blank_ :: Raw Line
-blank_ = Line $ Left (Blank () [] Nothing, LF)
+blank_ = Line $ Left (Blank (Ann ()) [] Nothing, LF)
 
 -- | Convert some data to a 'Line'
 class AsLine s where
@@ -481,11 +482,11 @@
 
 instance AsLine SmallStatement where
   line_ ss =
-    Line . Right $ SmallStatement (Indents [] ()) ss
+    Line . Right $ SmallStatement (Indents [] (Ann ())) ss
 
 instance AsLine SimpleStatement where
   line_ ss =
-    Line . Right . SmallStatement (Indents [] ()) $
+    Line . Right . SmallStatement (Indents [] (Ann ())) $
     MkSmallStatement ss [] Nothing Nothing (Just LF)
 
 instance AsLine CompoundStatement where
@@ -510,7 +511,7 @@
   line_ = Line . Right
 
 instance AsLine Expr where
-  line_ e = line_ $ Expr (e ^. exprAnn) e
+  line_ e = line_ $ Expr (e ^. annot) e
 
 instance HasExprs Line where
   _Exprs f (Line a) = Line <$> (_Right._Exprs) f a
@@ -562,7 +563,7 @@
 --
 -- @('.:') :: 'Raw' 'Expr' -> 'Raw' 'Expr' -> 'Raw' 'DictItem'@
 instance ColonSyntax Expr DictItem where
-  (.:) a = DictItem () a (MkColon [Space])
+  (.:) a = DictItem (Ann ()) a (MkColon [Space])
 
 -- | Function parameter type annotations
 --
@@ -589,22 +590,22 @@
 
 -- | See 'def_'
 instance StarSyntax Ident Param where
-  s_ i = StarParam () [] i Nothing
+  s_ i = StarParam (Ann ()) [] i Nothing
 
 -- | See 'def_'
 instance DoubleStarSyntax Ident Param where
-  ss_ i = DoubleStarParam () [] i Nothing
+  ss_ i = DoubleStarParam (Ann ()) [] i Nothing
 
 class StarSyntax s t | t -> s where
   s_ :: Raw s -> Raw t
 
 -- | See 'call_'
 instance StarSyntax Expr Arg where
-  s_ = StarArg () []
+  s_ = StarArg (Ann ()) []
 
 -- | See 'call_'
 instance DoubleStarSyntax Expr Arg where
-  ss_ = DoubleStarArg () []
+  ss_ = DoubleStarArg (Ann ()) []
 
 -- | Keyword parameters/arguments
 --
@@ -624,28 +625,28 @@
 -- def a(b, *):
 --     pass
 star_ :: Raw Param
-star_ = UnnamedStarParam () []
+star_ = UnnamedStarParam (Ann ()) []
 
 class DoubleStarSyntax s t | t -> s where
   ss_ :: Raw s -> Raw t
 
 -- | See 'dict_'
 instance DoubleStarSyntax Expr DictItem where
-  ss_ = DictUnpack () []
+  ss_ = DictUnpack (Ann ()) []
 
 -- | See 'def_'
 instance PositionalSyntax Param Ident where
-  p_ i = PositionalParam () i Nothing
+  p_ i = PositionalParam (Ann ()) i Nothing
 
 -- | See 'def_'
 instance KeywordSyntax Param where
-  k_ a = KeywordParam () a Nothing []
+  k_ a = KeywordParam (Ann ()) a Nothing []
 
 -- | See 'call_'
-instance PositionalSyntax Arg Expr where; p_ = PositionalArg ()
+instance PositionalSyntax Arg Expr where; p_ = PositionalArg (Ann ())
 
 -- | See 'call_'
-instance KeywordSyntax Arg where; k_ a = KeywordArg () a []
+instance KeywordSyntax Arg where; k_ a = KeywordArg (Ann ()) a []
 
 class ParametersSyntax s where
   -- | A faux-Lens that allows targeting 'Param's in-between existing formatting,
@@ -696,7 +697,7 @@
 decorated_ = setDecorators
 
 exprsToDecorators :: Indents () -> [Raw Expr] -> [Raw Decorator]
-exprsToDecorators is = fmap (\e -> Decorator () is (MkAt []) e Nothing LF [])
+exprsToDecorators is = fmap (\e -> Decorator (Ann ()) is (MkAt []) e Nothing LF [])
 
 instance DecoratorsSyntax Fundef where
   decorators = fdDecorators
@@ -723,7 +724,7 @@
     -- spaces.
     defaultIndent =
       fromMaybe
-        (Indents [replicate 4 Space ^. from indentWhitespaces] ())
+        (Indents [replicate 4 Space ^. from indentWhitespaces] (Ann ()))
         (e ^? gIndents)
 
     -- | The number of indentation chunks that precede the lines we're focusing on.
@@ -890,9 +891,9 @@
 mkFundef :: Raw Ident -> [Raw Line] -> Raw Fundef
 mkFundef name body =
   MkFundef
-  { _fdAnn = ()
+  { _fdAnn = Ann ()
   , _fdDecorators = []
-  , _fdIndents = Indents [] ()
+  , _fdIndents = Indents [] (Ann ())
   , _fdAsync = Nothing
   , _fdDefSpaces = pure Space
   , _fdName = name
@@ -900,7 +901,7 @@
   , _fdParameters = CommaSepNone
   , _fdRightParenSpaces = []
   , _fdReturnType = Nothing
-  , _fdBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _fdBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   }
 
 -- |
@@ -930,7 +931,7 @@
 mkCall :: Raw Expr -> Raw Call
 mkCall e =
   MkCall
-  { _callAnn = ()
+  { _callAnn = Ann ()
   , _callFunction = e
   , _callLeftParen = []
   , _callArguments = Nothing
@@ -976,8 +977,8 @@
 return_ :: Raw Expr -> Raw Statement
 return_ e =
   SmallStatement
-    (Indents [] ())
-    (MkSmallStatement (Return () [Space] $ Just e) [] Nothing Nothing (Just LF))
+    (Indents [] (Ann ()))
+    (MkSmallStatement (Return (Ann ()) [Space] $ Just e) [] Nothing Nothing (Just LF))
 
 -- | Turns an 'Expr' into a 'Statement'
 --
@@ -986,8 +987,8 @@
 expr_ :: Raw Expr -> Raw Statement
 expr_ e =
   SmallStatement
-    (Indents [] ())
-    (MkSmallStatement (Expr () e) [] Nothing Nothing (Just LF))
+    (Indents [] (Ann ()))
+    (MkSmallStatement (Expr (Ann ()) e) [] Nothing Nothing (Just LF))
 
 -- |
 -- >>> list_ [li_ $ var_ "a"]
@@ -1012,17 +1013,17 @@
   li_ = id
 
 instance AsListItem Expr where
-  li_ = ListItem ()
+  li_ = ListItem (Ann ())
 
 -- | See 'list_'
 instance StarSyntax Expr ListItem where
-  s_ = ListUnpack () [] []
+  s_ = ListUnpack (Ann ()) [] []
 
 instance e ~ Raw ListItem => AsList [e] where
-  list_ es = List () [] (listToCommaSep1' es) []
+  list_ es = List (Ann ()) [] (listToCommaSep1' es) []
 
 instance e ~ Comprehension Expr => AsList (Raw e) where
-  list_ c = ListComp () [] c []
+  list_ c = ListComp (Ann ()) [] c []
 
 newtype Guard v a = MkGuard { unGuard :: Either (CompFor v a) (CompIf v a) }
 
@@ -1035,7 +1036,7 @@
 -- >>> comp_ (var_ "a") (for_ $ var_ "a" `in_` var_ "b") []
 -- a for a in b
 instance ForSyntax (Raw CompFor) In where
-  for_ (MkIn a b) = CompFor () [Space] a [Space] b
+  for_ (MkIn a b) = CompFor (Ann ()) [Space] a [Space] b
 
 -- |
 -- @'for_' :: 'Raw' 'In' -> 'Raw' 'Guard'@
@@ -1043,7 +1044,7 @@
 -- >>> comp_ (var_ "a") (for_ $ var_ "a" `in_` var_ "b") [for_ $ var_ "c" `in_` var_ "d"]
 -- a for a in b for c in d
 instance ForSyntax (Raw Guard) In where
-  for_ (MkIn a b) = MkGuard . Left $ CompFor () [Space] a [Space] b
+  for_ (MkIn a b) = MkGuard . Left $ CompFor (Ann ()) [Space] a [Space] b
 
 class IfSyntax a where
   if_ :: Raw Expr -> a
@@ -1054,7 +1055,7 @@
 -- >>> comp_ (var_ "a") (for_ $ var_ "a" `in_` var_ "b") [if_ $ var_ "c" .== var_ "d"]
 -- a for a in b if c == d
 instance IfSyntax (Raw Guard) where
-  if_ = MkGuard . Right . CompIf () [Space]
+  if_ = MkGuard . Right . CompIf (Ann ()) [Space]
 
 -- |
 -- >>> set_ []
@@ -1082,24 +1083,24 @@
   si_ = id
 
 instance AsSetItem Expr where
-  si_ = SetItem ()
+  si_ = SetItem (Ann ())
 
 -- | See 'set_'
 instance StarSyntax Expr SetItem where
-  s_ = SetUnpack () [] []
+  s_ = SetUnpack (Ann ()) [] []
 
 instance e ~ Raw SetItem => AsSet [e] where
   set_ es =
     case es of
       [] -> call_ (var_ "set") []
-      a:as -> Set () [] ((a, zip (repeat (MkComma [Space])) as, Nothing) ^. _CommaSep1') []
+      a:as -> Set (Ann ()) [] ((a, zip (repeat (MkComma [Space])) as, Nothing) ^. _CommaSep1') []
 
 instance e ~ Comprehension SetItem => AsSet (Raw e) where
-  set_ c = SetComp () [] c []
+  set_ c = SetComp (Ann ()) [] c []
 
 comp_ :: Raw e -> Raw CompFor -> [Raw Guard] -> Raw (Comprehension e)
 comp_ val cfor guards =
-  Comprehension ()
+  Comprehension (Ann ())
     val
     (if null guards
      then cfor
@@ -1110,7 +1111,7 @@
 -- >>> gen_ $ comp_ (var_ "a") (for_ $ var_ "a" `in_` list_ [li_ $ int_ 1, li_ $ int_ 2, li_ $ int_ 3]) [if_ $ var_ "a" .== 2]
 -- (a for a in [1, 2, 3] if a == 2)
 gen_ :: Raw (Comprehension Expr) -> Raw Expr
-gen_ = Generator ()
+gen_ = Generator (Ann ())
 
 -- |
 -- >>> dict_ [var_ "a" .: 1]
@@ -1131,7 +1132,7 @@
 -- @'dict_' :: ['Raw' 'DictItem'] -> 'Raw' 'Expr'@
 instance e ~ Raw DictItem => AsDict [e] where
   dict_ ds =
-    Dict ()
+    Dict (Ann ())
     []
     (case ds of
        [] -> Nothing
@@ -1141,14 +1142,14 @@
 -- |
 -- @'dict_' :: 'Raw' ('Comprehension' 'DictItem') -> 'Raw' 'Expr'@
 instance e ~ Comprehension DictItem => AsDict (Raw e) where
-  dict_ comp = DictComp () [] comp []
+  dict_ comp = DictComp (Ann ()) [] comp []
 
 mkBinOp :: ([Whitespace] -> BinOp ()) -> Raw Expr -> Raw Expr -> Raw Expr
-mkBinOp bop a = BinOp () (a & trailingWhitespace .~ [Space]) (bop [Space])
+mkBinOp bop a = BinOp (Ann ()) (a & trailingWhitespace .~ [Space]) (bop [Space])
 
 -- | @a is b@
 is_ :: Raw Expr -> Raw Expr -> Raw Expr
-is_ = mkBinOp $ Is ()
+is_ = mkBinOp $ Is (Ann ())
 infixl 1 `is_`
 
 -- |
@@ -1169,19 +1170,19 @@
 --
 -- Does not have a precedence
 and_ :: Raw Expr -> Raw Expr -> Raw Expr
-and_ a = BinOp () (a & trailingWhitespace .~ [Space]) (BoolAnd () [Space])
+and_ a = BinOp (Ann ()) (a & trailingWhitespace .~ [Space]) (BoolAnd (Ann ()) [Space])
 
 -- | @a or b@
 --
 -- Does not have a precedence
 or_ :: Raw Expr -> Raw Expr -> Raw Expr
-or_ a = BinOp () (a & trailingWhitespace .~ [Space]) (BoolOr () [Space])
+or_ a = BinOp (Ann ()) (a & trailingWhitespace .~ [Space]) (BoolOr (Ann ()) [Space])
 
 -- |
 -- >>> var_ "a" `in_` var_ "b"
 -- a in b
 instance InSyntax Expr (Raw Expr) where
-  in_ = mkBinOp $ In ()
+  in_ = mkBinOp $ In (Ann ())
 
 -- | See 'for_'
 instance e ~ Raw Expr => InSyntax InList [e] where
@@ -1189,71 +1190,71 @@
 
 -- | @a not in b@
 notIn_ :: Raw Expr -> Raw Expr -> Raw Expr
-notIn_ = mkBinOp $ NotIn () [Space]
+notIn_ = mkBinOp $ NotIn (Ann ()) [Space]
 infixl 1 `notIn_`
 
 -- | @a is not b@
 isNot_ :: Raw Expr -> Raw Expr -> Raw Expr
-isNot_ = mkBinOp $ IsNot () [Space]
+isNot_ = mkBinOp $ IsNot (Ann ()) [Space]
 infixl 1 `isNot_`
 
 -- | @not a@
 not_ :: Raw Expr -> Raw Expr
-not_ = Not () [Space]
+not_ = Not (Ann ()) [Space]
 
 -- | @a == b@
 (.==) :: Raw Expr -> Raw Expr -> Raw Expr
-(.==) = mkBinOp $ Eq ()
+(.==) = mkBinOp $ Eq (Ann ())
 infixl 1 .==
 
 -- | @a < b@
 (.<) :: Raw Expr -> Raw Expr -> Raw Expr
-(.<) = mkBinOp $ Lt ()
+(.<) = mkBinOp $ Lt (Ann ())
 infixl 1 .<
 
 -- | @a <= b@
 (.<=) :: Raw Expr -> Raw Expr -> Raw Expr
-(.<=) = mkBinOp $ LtEq ()
+(.<=) = mkBinOp $ LtEq (Ann ())
 infixl 1 .<=
 
 -- | @a > b@
 (.>) :: Raw Expr -> Raw Expr -> Raw Expr
-(.>) = mkBinOp $ Gt ()
+(.>) = mkBinOp $ Gt (Ann ())
 infixl 1 .>
 
 -- | @a >= b@
 (.>=) :: Raw Expr -> Raw Expr -> Raw Expr
-(.>=) = mkBinOp $ GtEq ()
+(.>=) = mkBinOp $ GtEq (Ann ())
 infixl 1 .>=
 
 -- | @a != b@
 (.!=) :: Raw Expr -> Raw Expr -> Raw Expr
-(.!=) = mkBinOp $ NotEq ()
+(.!=) = mkBinOp $ NotEq (Ann ())
 infixl 1 .!=
 
 -- | @a | b@
 (.|) :: Raw Expr -> Raw Expr -> Raw Expr
-(.|) = mkBinOp $ BitOr ()
+(.|) = mkBinOp $ BitOr (Ann ())
 infixl 2 .|
 
 -- | @a ^ b@
 (.^) :: Raw Expr -> Raw Expr -> Raw Expr
-(.^) = mkBinOp $ BitXor ()
+(.^) = mkBinOp $ BitXor (Ann ())
 infixl 3 .^
 
 -- | @a & b@
 (.&) :: Raw Expr -> Raw Expr -> Raw Expr 
-(.&) = mkBinOp $ BitAnd ()
+(.&) = mkBinOp $ BitAnd (Ann ())
 infixl 4 .&
 
 -- | @a << b@
 (.<<) :: Raw Expr -> Raw Expr -> Raw Expr 
-(.<<) = mkBinOp $ ShiftLeft ()
+(.<<) = mkBinOp $ ShiftLeft (Ann ())
 infixl 5 .<<
 
 -- | @a >> b@
 (.>>) :: Raw Expr -> Raw Expr -> Raw Expr 
-(.>>) = mkBinOp $ ShiftRight ()
+(.>>) = mkBinOp $ ShiftRight (Ann ())
 infixl 5 .>>
 
 -- | @a + b@
@@ -1273,34 +1274,34 @@
 
 -- | @a \@ b@
 (.@) :: Raw Expr -> Raw Expr -> Raw Expr
-(.@) = mkBinOp $ At ()
+(.@) = mkBinOp $ At (Ann ())
 infixl 7 .@
 
 -- | @a / b@
 (./) :: Raw Expr -> Raw Expr -> Raw Expr
-(./) = mkBinOp $ Divide ()
+(./) = mkBinOp $ Divide (Ann ())
 infixl 7 ./
 
 -- | @a // b@
 (.//) :: Raw Expr -> Raw Expr -> Raw Expr
-(.//) = mkBinOp $ FloorDivide ()
+(.//) = mkBinOp $ FloorDivide (Ann ())
 infixl 7 .//
 
 -- | @a % b@
 (.%) :: Raw Expr -> Raw Expr -> Raw Expr
-(.%) = mkBinOp $ Percent ()
+(.%) = mkBinOp $ Percent (Ann ())
 infixl 7 .%
 
 -- | @a ** b@
 (.**) :: Raw Expr -> Raw Expr -> Raw Expr
-(.**) = mkBinOp $ Exp ()
+(.**) = mkBinOp $ Exp (Ann ())
 infixr 8 .**
 
 -- |
 -- >>> var_ "a" /> var_ "b"
 -- a.b
 (/>) :: Raw Expr -> Raw Ident -> Raw Expr
-(/>) a = Deref () a []
+(/>) a = Deref (Ann ()) a []
 infixl 9 />
 
 -- | @-a@
@@ -1309,11 +1310,11 @@
 
 -- | @+a@
 pos_ :: Raw Expr -> Raw Expr
-pos_ = UnOp () (Positive () [])
+pos_ = UnOp (Ann ()) (Positive (Ann ()) [])
 
 -- | @~a@
 compl_ :: Raw Expr -> Raw Expr
-compl_ = UnOp () (Complement () [])
+compl_ = UnOp (Ann ()) (Complement (Ann ()) [])
 
 -- | Convert a list of 'Line's to a 'Block', giving them 4 spaces of indentation
 linesToBlockIndented :: [Raw Line] -> Raw Block
@@ -1347,11 +1348,11 @@
 mkWhile :: Raw Expr -> [Raw Line] -> Raw While
 mkWhile cond body =
   MkWhile
-  { _whileAnn = ()
-  , _whileIndents = Indents [] ()
+  { _whileAnn = Ann ()
+  , _whileIndents = Indents [] (Ann ())
   , _whileWhile = [Space]
   , _whileCond = cond
-  , _whileBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _whileBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   , _whileElse = Nothing
   }
 
@@ -1362,11 +1363,11 @@
 mkIf :: Raw Expr -> [Raw Line] -> Raw If
 mkIf cond body =
   MkIf
-  { _ifAnn = ()
-  , _ifIndents = Indents [] ()
+  { _ifAnn = Ann ()
+  , _ifIndents = Indents [] (Ann ())
   , _ifIf = [Space]
   , _ifCond = cond
-  , _ifBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _ifBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   , _ifElifs = []
   , _ifElse = Nothing
   }
@@ -1396,13 +1397,13 @@
 ifThen_ = mkIf
 
 var_ :: String -> Raw Expr
-var_ s = Ident $ MkIdent () s []
+var_ s = Ident (Ann ()) $ MkIdent (Ann ()) s []
 
 -- |
 -- >>> none_
 -- None
 none_ :: Raw Expr
-none_ = None () []
+none_ = None (Ann ()) []
 
 -- | @'Raw' 'Expr'@ has a 'Num' instance, but sometimes we need to name integers
 -- explicitly
@@ -1418,17 +1419,17 @@
 pass_ :: Raw Statement
 pass_ =
   SmallStatement
-    (Indents [] ())
-    (MkSmallStatement (Pass () []) [] Nothing Nothing (Just LF))
+    (Indents [] (Ann ()))
+    (MkSmallStatement (Pass (Ann ()) []) [] Nothing Nothing (Just LF))
 
 -- | Create a minimal valid 'Elif'
 mkElif :: Raw Expr -> [Raw Line] -> Raw Elif
 mkElif cond body =
   MkElif
-  { _elifIndents = Indents [] ()
+  { _elifIndents = Indents [] (Ann ())
   , _elifElif = [Space]
   , _elifCond = cond
-  , _elifBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _elifBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   }
 
 elif_ :: Raw Expr -> [Raw Line] -> Raw If -> Raw If
@@ -1438,9 +1439,9 @@
 mkElse :: [Raw Line] -> Raw Else
 mkElse body =
   MkElse
-  { _elseIndents = Indents [] ()
+  { _elseIndents = Indents [] (Ann ())
   , _elseElse = []
-  , _elseBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _elseBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   }
 
 class ElseSyntax s where
@@ -1494,20 +1495,20 @@
 break_ :: Raw Statement
 break_ =
   SmallStatement
-    (Indents [] ())
-    (MkSmallStatement (Break () []) [] Nothing Nothing (Just LF))
+    (Indents [] (Ann ()))
+    (MkSmallStatement (Break (Ann ()) []) [] Nothing Nothing (Just LF))
 
 -- |
 -- >>> true_
 -- True
 true_ :: Raw Expr
-true_ = Bool () True []
+true_ = Bool (Ann ()) True []
 
 -- |
 -- >>> false_
 -- False
 false_ :: Raw Expr
-false_ = Bool () False []
+false_ = Bool (Ann ()) False []
 
 -- | Double-quoted string
 --
@@ -1515,8 +1516,8 @@
 -- "asdf"
 str_ :: String -> Raw Expr
 str_ s =
-  String () . pure $
-  StringLiteral () Nothing ShortString DoubleQuote (Char_lit <$> s) []
+  String (Ann ()) . pure $
+  StringLiteral (Ann ()) Nothing ShortString DoubleQuote (Char_lit <$> s) []
 
 -- | Single-quoted string
 --
@@ -1524,8 +1525,8 @@
 -- 'asdf'
 str'_ :: String -> Raw Expr
 str'_ s =
-  String () . pure $
-  StringLiteral () Nothing ShortString SingleQuote (Char_lit <$> s) []
+  String (Ann ()) . pure $
+  StringLiteral (Ann ()) Nothing ShortString SingleQuote (Char_lit <$> s) []
 
 -- | Long double-quoted string
 --
@@ -1533,8 +1534,8 @@
 -- """asdf"""
 longStr_ :: String -> Raw Expr
 longStr_ s =
-  String () . pure $
-  StringLiteral () Nothing LongString DoubleQuote (Char_lit <$> s) []
+  String (Ann ()) . pure $
+  StringLiteral (Ann ()) Nothing LongString DoubleQuote (Char_lit <$> s) []
 
 -- | Long single-quoted string
 --
@@ -1542,15 +1543,18 @@
 -- '''asdf'''
 longStr'_ :: String -> Raw Expr
 longStr'_ s =
-  String () . pure $
-  StringLiteral () Nothing LongString SingleQuote (Char_lit <$> s) []
+  String (Ann ()) . pure $
+  StringLiteral (Ann ()) Nothing LongString SingleQuote (Char_lit <$> s) []
 
 mkAugAssign :: AugAssignOp -> Raw Expr -> Raw Expr -> Raw Statement
 mkAugAssign at a b =
   SmallStatement
-    (Indents [] ())
+    (Indents [] (Ann ()))
     (MkSmallStatement
-       (AugAssign () (a & trailingWhitespace .~ [Space]) (MkAugAssign at () [Space]) b)
+       (AugAssign
+          (Ann ())
+          (a & trailingWhitespace .~ [Space])
+          (MkAugAssign (Ann ()) at [Space]) b)
        []
        Nothing
        Nothing
@@ -1567,9 +1571,9 @@
 chainEq t [] = expr_ t
 chainEq t (a:as) =
   SmallStatement
-    (Indents [] ())
+    (Indents [] (Ann ()))
     (MkSmallStatement
-       (Assign () t $ (,) (MkEquals [Space]) <$> (a :| as))
+       (Assign (Ann ()) t $ (,) (MkEquals [Space]) <$> (a :| as))
        []
        Nothing
        Nothing
@@ -1579,9 +1583,9 @@
 (.=) :: Raw Expr -> Raw Expr -> Raw Statement
 (.=) a b =
   SmallStatement
-    (Indents [] ())
+    (Indents [] (Ann ()))
     (MkSmallStatement
-       (Assign () (a & trailingWhitespace .~ [Space]) $ pure (MkEquals [Space], b))
+       (Assign (Ann ()) (a & trailingWhitespace .~ [Space]) $ pure (MkEquals [Space], b))
        []
        Nothing
        Nothing
@@ -1656,17 +1660,17 @@
 mkFor :: Raw Expr -> [Raw Expr] -> [Raw Line] -> Raw For
 mkFor binder collection body =
   MkFor
-  { _forAnn = ()
-  , _forIndents = Indents [] ()
+  { _forAnn = Ann ()
+  , _forIndents = Indents [] (Ann ())
   , _forAsync = Nothing
   , _forFor = [Space]
   , _forBinder = binder & trailingWhitespace .~ [Space]
   , _forIn = [Space]
   , _forCollection =
       fromMaybe
-        (CommaSepOne1' (Unit () [] []) Nothing)
+        (CommaSepOne1' (Unit (Ann ()) [] []) Nothing)
         (listToCommaSep1' collection)
-  , _forBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _forBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   , _forElse = Nothing
   }
 
@@ -1702,29 +1706,29 @@
 mkFinally :: [Raw Line] -> Raw Finally
 mkFinally body =
   MkFinally
-  { _finallyIndents = Indents [] ()
+  { _finallyIndents = Indents [] (Ann ())
   , _finallyFinally = []
-  , _finallyBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _finallyBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   }
 
 -- | Create a minimal valid 'Except'
 mkExcept :: [Raw Line] -> Raw Except
 mkExcept body =
   MkExcept
-  { _exceptIndents = Indents [] ()
+  { _exceptIndents = Indents [] (Ann ())
   , _exceptExcept = []
   , _exceptExceptAs = Nothing
-  , _exceptBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _exceptBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   }
 
 -- | Create a minimal valid 'TryExcept'
 mkTryExcept :: [Raw Line] -> Raw Except -> Raw TryExcept
 mkTryExcept body except =
   MkTryExcept
-  { _teAnn = ()
-  , _teIndents = Indents [] ()
+  { _teAnn = Ann ()
+  , _teIndents = Indents [] (Ann ())
   , _teTry = [Space]
-  , _teBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _teBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   , _teExcepts = pure except
   , _teElse = Nothing
   , _teFinally = Nothing
@@ -1734,10 +1738,10 @@
 mkTryFinally :: [Raw Line] -> [Raw Line] -> Raw TryFinally
 mkTryFinally body fBody =
   MkTryFinally
-  { _tfAnn = ()
-  , _tfIndents = Indents [] ()
+  { _tfAnn = Ann ()
+  , _tfIndents = Indents [] (Ann ())
   , _tfTry = [Space]
-  , _tfBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _tfBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   , _tfFinally = mkFinally fBody
   }
 
@@ -1807,7 +1811,7 @@
   toExceptAs = id
 
 instance AsExceptAs Expr where
-  toExceptAs e = ExceptAs () e Nothing
+  toExceptAs e = ExceptAs (Ann ()) e Nothing
 
 class ExceptSyntax s where
   except_ :: [Raw Line] -> s -> Raw TryExcept
@@ -1915,7 +1919,7 @@
 
 -- | See 'exceptAs_'
 instance As Expr Ident ExceptAs where
-  as_ e name = ExceptAs () e $ Just ([Space], name)
+  as_ e name = ExceptAs (Ann ()) e $ Just ([Space], name)
 
 -- |
 -- >>> class_ "A" [] [line_ pass_]
@@ -1934,13 +1938,13 @@
 mkClassDef :: Raw Ident -> [Raw Line] -> Raw ClassDef
 mkClassDef name body =
   MkClassDef
-  { _cdAnn = ()
+  { _cdAnn = Ann ()
   , _cdDecorators = []
-  , _cdIndents = Indents [] ()
+  , _cdIndents = Indents [] (Ann ())
   , _cdClass = Space :| []
   , _cdName = name
   , _cdArguments = Nothing
-  , _cdBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _cdBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   }
 
 instance BodySyntax ClassDef where
@@ -1972,12 +1976,12 @@
 mkWith :: NonEmpty (Raw WithItem) -> [Raw Line] -> Raw With
 mkWith items body =
   MkWith
-  { _withAnn = ()
-  , _withIndents = Indents [] ()
+  { _withAnn = Ann ()
+  , _withIndents = Indents [] (Ann ())
   , _withAsync = Nothing
   , _withWith = [Space]
   , _withItems = listToCommaSep1 items
-  , _withBody = SuiteMany () (MkColon []) Nothing LF $ linesToBlockIndented body
+  , _withBody = SuiteMany (Ann ()) (MkColon []) Nothing LF $ linesToBlockIndented body
   }
 
 -- |
@@ -2002,17 +2006,17 @@
 with_ items = mkWith (toWithItem <$> items)
 
 withItem_ :: Raw Expr -> Maybe (Raw Expr) -> Raw WithItem
-withItem_ a b = WithItem () a ((,) [Space] <$> b)
+withItem_ a b = WithItem (Ann ()) a ((,) [Space] <$> b)
 
 -- | See 'with_'
 instance As Expr Expr WithItem where
-  as_ a b = WithItem () a $ Just ([Space], b)
+  as_ a b = WithItem (Ann ()) a $ Just ([Space], b)
 
 class AsWithItem s where
   toWithItem :: Raw s -> Raw WithItem
 
 instance AsWithItem Expr where
-  toWithItem e = WithItem () e Nothing
+  toWithItem e = WithItem (Ann ()) e Nothing
 
 instance AsWithItem WithItem where
   toWithItem = id
@@ -2028,7 +2032,7 @@
 -- >>> ellipsis_
 -- ...
 ellipsis_ :: Raw Expr
-ellipsis_ = Ellipsis () []
+ellipsis_ = Ellipsis (Ann ()) []
 
 class AsTupleItem e where
   -- | Create a 'TupleItem'
@@ -2036,10 +2040,10 @@
 
 -- | See 'tuple_'
 instance StarSyntax Expr TupleItem where
-  s_ = TupleUnpack () [] []
+  s_ = TupleUnpack (Ann ()) [] []
 
 instance AsTupleItem Expr where
-  ti_ = TupleItem ()
+  ti_ = TupleItem (Ann ())
 
 instance AsTupleItem TupleItem where
   ti_ = id
@@ -2060,25 +2064,25 @@
 -- >>> tuple_ [ti_ $ var_ "a", s_ $ var_ "b"]
 -- a, *b
 tuple_ :: [Raw TupleItem] -> Raw Expr
-tuple_ [] = Unit () [] []
+tuple_ [] = Unit (Ann ()) [] []
 tuple_ (a:as) =
   case as of
-    [] -> Tuple () (ti_ a) (MkComma []) Nothing
+    [] -> Tuple (Ann ()) (ti_ a) (MkComma []) Nothing
     b:bs ->
-      Tuple () a (MkComma [Space]) . Just $
+      Tuple (Ann ()) a (MkComma [Space]) . Just $
       (b, zip (repeat (MkComma [Space])) bs, Nothing) ^. _CommaSep1'
 
 -- |
 -- >>> await (var_ "a")
 -- await a
 await_ :: Raw Expr -> Raw Expr
-await_ = Await () [Space]
+await_ = Await (Ann ()) [Space]
 
 -- |
 -- >>> ifThenElse_ (var_ "a") (var_ "b") (var_ "c")
 -- a if b else c
 ifThenElse_ :: Raw Expr -> Raw Expr -> Raw Expr -> Raw Expr
-ifThenElse_ a b = Ternary () a [Space] b [Space]
+ifThenElse_ a b = Ternary (Ann ()) a [Space] b [Space]
 
 -- |
 -- >>> lambda_ [p_ "x"] "x"
@@ -2094,7 +2098,7 @@
 -- lambda x, y=2, *z, **w: a
 lambda_ :: [Raw Param] -> Raw Expr -> Raw Expr
 lambda_ params =
-  Lambda ()
+  Lambda (Ann ())
     (if null params then [] else [Space])
     (listToCommaSep params)
     (MkColon [Space])
@@ -2109,13 +2113,13 @@
 -- >>> yield_ [var_ "a", var_ "b"]
 -- yield a, b
 yield_ :: [Raw Expr] -> Raw Expr
-yield_ as = Yield () (foldr (\_ _ -> [Space]) [] as) (listToCommaSep as)
+yield_ as = Yield (Ann ()) (foldr (\_ _ -> [Space]) [] as) (listToCommaSep as)
 
 -- |
 -- >>> yieldFrom_ (var_ "a")
 -- yield from a
 yieldFrom_ :: Raw Expr -> Raw Expr
-yieldFrom_ = YieldFrom () [Space] [Space]
+yieldFrom_ = YieldFrom (Ann ()) [Space] [Space]
 
 -- | The slice with no bounds
 --
@@ -2227,7 +2231,7 @@
 -- a[(1, *b)]
 subs_ :: Raw Expr -> Raw Expr -> Raw Expr
 subs_ a e =
-  Subscript () a
+  Subscript (Ann ()) a
     []
     (exprToSubscript e ^. _CommaSep1')
     []
diff --git a/src/Language/Python/Internal/Lexer.hs b/src/Language/Python/Internal/Lexer.hs
--- a/src/Language/Python/Internal/Lexer.hs
+++ b/src/Language/Python/Internal/Lexer.hs
@@ -69,6 +69,7 @@
 import qualified Text.Megaparsec as Parsec
 
 import Language.Python.Internal.Token (PyToken(..), pyTokenAnn)
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Comment
 import Language.Python.Syntax.Ident
 import Language.Python.Syntax.Numbers
@@ -113,7 +114,8 @@
 
 parseComment :: (CharParsing m, Monad m) => m (SrcInfo -> PyToken SrcInfo)
 parseComment =
-  (\a b -> TkComment (MkComment b a)) <$ char '#' <*> many (satisfy (`notElem` ['\r', '\n']))
+  (\a b -> TkComment (MkComment (Ann b) a)) <$ char '#' <*>
+  many (satisfy (`notElem` ['\r', '\n']))
 
 stringOrBytesPrefix
   :: CharParsing m
@@ -197,27 +199,29 @@
           (\x j ann ->
              case x of
                Nothing ->
-                 maybe (TkInt $ IntLiteralDec ann n) (TkImag . ImagLiteralInt ann n) j
+                 maybe
+                   (TkInt $ IntLiteralDec (Ann ann) n)
+                   (TkImag . ImagLiteralInt (Ann ann) n) j
                Just (Right e) ->
                  let
-                   f = FloatLiteralWhole ann n e
+                   f = FloatLiteralWhole (Ann ann) n e
                  in
-                   maybe (TkFloat f) (TkImag . ImagLiteralFloat ann f) j
+                   maybe (TkFloat f) (TkImag . ImagLiteralFloat (Ann ann) f) j
                Just (Left (Left e)) ->
                  let
-                   f = FloatLiteralFull ann n (Just (That e))
+                   f = FloatLiteralFull (Ann ann) n (Just (That e))
                  in
-                   maybe (TkFloat f) (TkImag . ImagLiteralFloat ann f) j
+                   maybe (TkFloat f) (TkImag . ImagLiteralFloat (Ann ann) f) j
                Just (Left (Right (a, b))) ->
                  let
-                   f = FloatLiteralFull ann n $
+                   f = FloatLiteralFull (Ann ann) n $
                      case (a, b) of
                        (Nothing, Nothing) -> Nothing
                        (Just x, Nothing) -> Just $ This x
                        (Nothing, Just x) -> Just $ That x
                        (Just x, Just y) -> Just $ These x y
                  in
-                   maybe (TkFloat f) (TkImag . ImagLiteralFloat ann f) j) <$>
+                   maybe (TkFloat f) (TkImag . ImagLiteralFloat (Ann ann) f) j) <$>
           optional
             (Left <$ char '.' <*>
              (Left <$> floatExp <|>
@@ -227,28 +231,30 @@
         Nothing ->
           (\a b j ann ->
              let
-               f = FloatLiteralPoint ann a b
+               f = FloatLiteralPoint (Ann ann) a b
              in
-               maybe (TkFloat f) (TkImag . ImagLiteralFloat ann f) j) <$>
+               maybe (TkFloat f) (TkImag . ImagLiteralFloat (Ann ann) f) j) <$>
           -- try is necessary here to prevent the intercepting of dereference tokens
           try (char '.' *> some1 parseDecimal) <*>
           optional floatExp <*>
           optional jJ
     Just z ->
-      (\xX a b -> TkInt (IntLiteralHex b xX a)) <$>
+      (\xX a b -> TkInt (IntLiteralHex (Ann b) xX a)) <$>
       (True <$ char 'X' <|> False <$ char 'x') <*>
       some1 parseHeXaDeCiMaL
       <|>
-      (\bB a b -> TkInt (IntLiteralBin b bB a)) <$>
+      (\bB a b -> TkInt (IntLiteralBin (Ann b) bB a)) <$>
       (True <$ char 'B' <|> False <$ char 'b') <*>
       some1 parseBinary
       <|>
-      (\oO a b -> TkInt (IntLiteralOct b oO a)) <$>
+      (\oO a b -> TkInt (IntLiteralOct (Ann b) oO a)) <$>
       (True <$ char 'O' <|> False <$ char 'o') <*>
       some1 parseOctal
       <|>
       (\n j a ->
-         maybe (TkInt $ IntLiteralDec a (z :| n)) (TkImag . ImagLiteralInt a (z :| n)) j) <$>
+         maybe
+           (TkInt $ IntLiteralDec (Ann a) (z :| n))
+           (TkImag . ImagLiteralInt (Ann a) (z :| n)) j) <$>
       try (many parse0 <* notFollowedBy (char '.' <|> char 'e' <|> char 'E' <|> digit)) <*>
       optional jJ
       <|>
@@ -256,20 +262,20 @@
          case a of
            Left (Left (b, c, j)) ->
              let
-               f = FloatLiteralFull ann (z :| n') $
+               f = FloatLiteralFull (Ann ann) (z :| n') $
                  case (b, c) of
                    (Nothing, Nothing) -> Nothing
                    (Just x, Nothing) -> Just $ This x
                    (Nothing, Just x) -> Just $ That x
                    (Just x, Just y) -> Just $ These x y
              in
-               maybe (TkFloat f) (TkImag . ImagLiteralFloat ann f) j
+               maybe (TkFloat f) (TkImag . ImagLiteralFloat (Ann ann) f) j
            Left (Right (x, j)) ->
              let
-               f = FloatLiteralWhole ann (z :| n') x
+               f = FloatLiteralWhole (Ann ann) (z :| n') x
              in
-               maybe (TkFloat f) (TkImag . ImagLiteralFloat ann f) j
-           Right j -> TkImag $ ImagLiteralInt ann (z :| n') j) <$>
+               maybe (TkFloat f) (TkImag . ImagLiteralFloat (Ann ann) f) j
+           Right j -> TkImag $ ImagLiteralInt (Ann ann) (z :| n') j) <$>
       many parseDecimal <*>
       (Left <$>
        (Left <$>
@@ -724,14 +730,14 @@
       let
         leaps' = leaps FingerTree.|> Summed n
       in
-        TkIndent a (Indents (splitIndents leaps' i) a) : go leaps' is
+        TkIndent a (Indents (splitIndents leaps' i) (Ann a)) : go leaps' is
     go leaps (Dedent a : is) =
       case FingerTree.viewr leaps of
         FingerTree.EmptyR -> error "impossible"
         leaps' FingerTree.:> _ -> TkDedent a : go leaps' is
     go leaps (IndentedLine ll : is) = logicalLineToTokens ll <> go leaps is
     go leaps (Level i a : is) =
-      TkLevel a (Indents (splitIndents leaps $ NonEmpty.toList i ^. from indentWhitespaces) a) : go leaps is
+      TkLevel a (Indents (splitIndents leaps $ NonEmpty.toList i ^. from indentWhitespaces) (Ann a)) : go leaps is
 
 -- | Insert indent and dedent tokens
 --
diff --git a/src/Language/Python/Internal/Parse.hs b/src/Language/Python/Internal/Parse.hs
--- a/src/Language/Python/Internal/Parse.hs
+++ b/src/Language/Python/Internal/Parse.hs
@@ -128,13 +128,13 @@
 import Language.Python.Internal.Lexer (SrcInfo(..), withSrcInfo)
 import Language.Python.Internal.Syntax.IR
 import Language.Python.Internal.Token
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.AugAssign
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Comment
 import Language.Python.Syntax.Ident
 import Language.Python.Syntax.Import
 import Language.Python.Syntax.ModuleNames
-import Language.Python.Syntax.Numbers
 import Language.Python.Syntax.Operator.Binary
 import Language.Python.Syntax.Operator.Unary
 import Language.Python.Syntax.Punctuation
@@ -276,7 +276,7 @@
 
 identifier :: MonadParsec e PyTokens m => m Whitespace -> m (Ident '[] SrcInfo)
 identifier ws =
-  (\(TkIdent n ann) -> MkIdent ann n) <$>
+  (\(TkIdent n ann) -> MkIdent (Ann ann) n) <$>
   satisfy (\case; TkIdent{} -> True; _ -> False) <*>
   many ws
 
@@ -305,30 +305,30 @@
 
 integer :: MonadParsec e PyTokens m => m Whitespace -> m (Expr SrcInfo)
 integer ws =
-  (\(TkInt n) -> Int (_intLiteralAnn n) n) <$>
+  (\(TkInt n) -> Int (n ^. annot_) n) <$>
   satisfy (\case; TkInt{} -> True; _ -> False) <*>
   many ws
 
 float :: MonadParsec e PyTokens m => m Whitespace -> m (Expr SrcInfo)
 float ws =
-  (\(TkFloat n) -> Float (_floatLiteralAnn n) n) <$>
+  (\(TkFloat n) -> Float (n ^. annot_) n) <$>
   satisfy (\case; TkFloat{} -> True; _ -> False) <*>
   many ws
 
 imag :: MonadParsec e PyTokens m => m Whitespace -> m (Expr SrcInfo)
 imag ws =
-  (\(TkImag n) -> Imag (_imagLiteralAnn n) n) <$>
+  (\(TkImag n) -> Imag (n ^. annot_) n) <$>
   satisfy (\case; TkImag{} -> True; _ -> False) <*>
   many ws
 
 stringOrBytes :: MonadParsec e PyTokens m => m Whitespace -> m (Expr SrcInfo)
 stringOrBytes ws =
-  fmap (\vs -> String (_stringLiteralAnn $ NonEmpty.head vs) vs) . some1 $
+  fmap (\vs -> String (view annot_ $ NonEmpty.head vs) vs) . some1 $
   (\case
-     TkString sp qt st val ann -> StringLiteral ann sp qt st val
-     TkBytes sp qt st val ann -> BytesLiteral ann sp qt st val
-     TkRawString sp st qt val ann -> RawStringLiteral ann sp st qt val
-     TkRawBytes sp st qt val ann -> RawBytesLiteral ann sp st qt val
+     TkString sp qt st val ann -> StringLiteral (Ann ann) sp qt st val
+     TkBytes sp qt st val ann -> BytesLiteral (Ann ann) sp qt st val
+     TkRawString sp st qt val ann -> RawStringLiteral (Ann ann) sp st qt val
+     TkRawBytes sp st qt val ann -> RawBytesLiteral (Ann ann) sp st qt val
      _ -> error "impossible") <$>
   satisfy
     (\case
@@ -369,7 +369,7 @@
 
 semicolon :: MonadParsec e PyTokens m => m Whitespace -> m (PyToken SrcInfo, Semicolon SrcInfo)
 semicolon ws =
-  (\(a, b) -> (a, MkSemicolon (pyTokenAnn a) b)) <$>
+  (\(a, b) -> (a, MkSemicolon (Ann $ pyTokenAnn a) b)) <$>
   token ws (\case; TkSemicolon{} -> True; _ -> False) ";"
 
 exprList :: MonadParsec e PyTokens m => m Whitespace -> m (Expr SrcInfo)
@@ -479,11 +479,11 @@
 orTest ws = binOp orOp andTest
   where
     orOp =
-      (\(tk, ws) -> BoolOr (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> BoolOr (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkOr{} -> True; _ -> False) "or"
 
     andOp =
-      (\(tk, ws) -> BoolAnd (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> BoolAnd (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkAnd{} -> True; _ -> False) "and"
     andTest = binOp andOp notTest
 
@@ -493,49 +493,49 @@
       comparison
 
     compOp =
-      (\(tk, ws) -> maybe (Is (pyTokenAnn tk) ws) (IsNot (pyTokenAnn tk) ws)) <$>
+      (\(tk, ws) -> maybe (Is (Ann $ pyTokenAnn tk) ws) (IsNot (Ann $ pyTokenAnn tk) ws)) <$>
       token ws (\case; TkIs{} -> True; _ -> False) "is" <*>
       optional (snd <$> token ws (\case; TkNot{} -> True; _ -> False) "not")
 
       <|>
 
-      (\(tk, ws) -> NotIn (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> NotIn (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkNot{} -> True; _ -> False) "not" <*>
       (snd <$> token ws (\case; TkIn{} -> True; _ -> False) "in")
 
       <|>
 
-      (\(tk, ws) -> In (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> In (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkIn{} -> True; _ -> False) "in"
 
       <|>
 
-      (\(tk, ws) -> Eq (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> Eq (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkDoubleEq{} -> True; _ -> False) "=="
 
       <|>
 
-      (\(tk, ws) -> Lt (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> Lt (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkLt{} -> True; _ -> False) "<"
 
       <|>
 
-      (\(tk, ws) -> LtEq (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> LtEq (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkLte{} -> True; _ -> False) "<="
 
       <|>
 
-      (\(tk, ws) -> Gt (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> Gt (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkGt{} -> True; _ -> False) ">"
 
       <|>
 
-      (\(tk, ws) -> GtEq (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> GtEq (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkGte{} -> True; _ -> False) ">="
 
       <|>
 
-      (\(tk, ws) -> NotEq (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> NotEq (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkBangEq{} -> True; _ -> False) "!="
 
     comparison = binOp compOp $ orExpr ws
@@ -598,84 +598,84 @@
 orExpr :: MonadParsec e PyTokens m => m Whitespace -> m (Expr SrcInfo)
 orExpr ws =
   binOp
-    ((\(tk, ws) -> BitOr (pyTokenAnn tk) ws) <$>
+    ((\(tk, ws) -> BitOr (Ann $ pyTokenAnn tk) ws) <$>
      token ws (\case; TkPipe{} -> True; _ -> False) "|")
     xorExpr
   where
     xorExpr =
       binOp
-        ((\(tk, ws) -> BitXor (pyTokenAnn tk) ws) <$>
+        ((\(tk, ws) -> BitXor (Ann $ pyTokenAnn tk) ws) <$>
          token ws (\case; TkCaret{} -> True; _ -> False) "^")
         andExpr
 
     andExpr =
       binOp
-        ((\(tk, ws) -> BitAnd (pyTokenAnn tk) ws) <$>
+        ((\(tk, ws) -> BitAnd (Ann $ pyTokenAnn tk) ws) <$>
          token ws (\case; TkAmpersand{} -> True; _ -> False) "&")
         shiftExpr
 
     shiftExpr =
       binOp
-        ((\(tk, ws) -> ShiftLeft (pyTokenAnn tk) ws) <$>
+        ((\(tk, ws) -> ShiftLeft (Ann $ pyTokenAnn tk) ws) <$>
          token ws (\case; TkShiftLeft{} -> True; _ -> False) "<<"
 
          <|>
 
-         (\(tk, ws) -> ShiftRight (pyTokenAnn tk) ws) <$>
+         (\(tk, ws) -> ShiftRight (Ann $ pyTokenAnn tk) ws) <$>
          token ws (\case; TkShiftRight{} -> True; _ -> False) ">>")
         arithExpr
 
     arithOp =
-      (\(tk, ws) -> Plus (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> Plus (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkPlus{} -> True; _ -> False) "+"
 
       <|>
 
-      (\(tk, ws) -> Minus (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> Minus (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkMinus{} -> True; _ -> False) "-"
 
     arithExpr = binOp arithOp term
 
     termOp =
-      (\(tk, ws) -> Multiply (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> Multiply (Ann $ pyTokenAnn tk) ws) <$>
       star ws
 
       <|>
 
-      (\(tk, ws) -> At (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> At (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkAt{} -> True; _ -> False) "@"
 
       <|>
 
-      (\(tk, ws) -> Divide (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> Divide (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkSlash{} -> True; _ -> False) "/"
 
       <|>
 
-      (\(tk, ws) -> FloorDivide (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> FloorDivide (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkDoubleSlash{} -> True; _ -> False) "//"
 
       <|>
 
-      (\(tk, ws) -> Percent (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> Percent (Ann $ pyTokenAnn tk) ws) <$>
       token ws (\case; TkPercent{} -> True; _ -> False) "%"
 
     term = binOp termOp factor
 
     factor =
-      ((\(tk, s) -> let ann = pyTokenAnn tk in UnOp ann (Negate ann s)) <$>
+      ((\(tk, s) -> let ann = pyTokenAnn tk in UnOp ann (Negate (Ann ann) s)) <$>
        token ws (\case; TkMinus{} -> True; _ -> False) "-"
        <|>
-       (\(tk, s) -> let ann = pyTokenAnn tk in UnOp ann (Positive ann s)) <$>
+       (\(tk, s) -> let ann = pyTokenAnn tk in UnOp ann (Positive (Ann ann) s)) <$>
        token ws (\case; TkPlus{} -> True; _ -> False) "+"
        <|>
-       (\(tk, s) -> let ann = pyTokenAnn tk in UnOp ann (Complement ann s)) <$>
+       (\(tk, s) -> let ann = pyTokenAnn tk in UnOp ann (Complement (Ann ann) s)) <$>
        token ws (\case; TkTilde{} -> True; _ -> False) "~") <*> factor
       <|>
       power
 
     powerOp =
-      (\(tk, ws) -> Exp (pyTokenAnn tk) ws) <$>
+      (\(tk, ws) -> Exp (Ann $ pyTokenAnn tk) ws) <$>
       doubleStar ws
 
     power =
@@ -843,7 +843,7 @@
       float ws <|>
       imag ws <|>
       stringOrBytes ws <|>
-      Ident <$> identifier ws <|>
+      (\i -> Ident (i ^. annot_) i) <$> identifier ws <|>
       parensOrUnit
 
 simpleStatement :: MonadParsec e PyTokens m => m (SimpleStatement SrcInfo)
@@ -886,69 +886,60 @@
       uncurry (Continue . pyTokenAnn) <$>
       token space (\case; TkContinue{} -> True; _ -> False) "continue"
 
+    mkAugAssign ctor match name =
+      (\(tk, s) -> MkAugAssign (Ann $ pyTokenAnn tk) ctor s) <$>
+      token space match name
+
     augAssign =
-      (\(tk, s) -> MkAugAssign PlusEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkPlusEq{} -> True; _ -> False) "+="
+      mkAugAssign PlusEq (\case; TkPlusEq{} -> True; _ -> False) "+="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign MinusEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkMinusEq{} -> True; _ -> False) "-="
+      mkAugAssign MinusEq (\case; TkMinusEq{} -> True; _ -> False) "-="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign AtEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkAtEq{} -> True; _ -> False) "@="
+      mkAugAssign AtEq (\case; TkAtEq{} -> True; _ -> False) "@="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign StarEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkStarEq{} -> True; _ -> False) "*="
+      mkAugAssign StarEq (\case; TkStarEq{} -> True; _ -> False) "*="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign SlashEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkSlashEq{} -> True; _ -> False) "/="
+      mkAugAssign SlashEq (\case; TkSlashEq{} -> True; _ -> False) "/="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign PercentEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkPercentEq{} -> True; _ -> False) "%="
+      mkAugAssign PercentEq (\case; TkPercentEq{} -> True; _ -> False) "%="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign AmpersandEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkAmpersandEq{} -> True; _ -> False) "&="
+      mkAugAssign AmpersandEq (\case; TkAmpersandEq{} -> True; _ -> False) "&="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign PipeEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkPipeEq{} -> True; _ -> False) "|="
+      mkAugAssign PipeEq (\case; TkPipeEq{} -> True; _ -> False) "|="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign CaretEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkCaretEq{} -> True; _ -> False) "^="
+      mkAugAssign CaretEq (\case; TkCaretEq{} -> True; _ -> False) "^="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign ShiftLeftEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkShiftLeftEq{} -> True; _ -> False) "<<="
+      mkAugAssign ShiftLeftEq (\case; TkShiftLeftEq{} -> True; _ -> False) "<<="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign ShiftRightEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkShiftRightEq{} -> True; _ -> False) ">>="
+      mkAugAssign ShiftRightEq (\case; TkShiftRightEq{} -> True; _ -> False) ">>="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign DoubleStarEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkDoubleStarEq{} -> True; _ -> False) "**="
+      mkAugAssign DoubleStarEq (\case; TkDoubleStarEq{} -> True; _ -> False) "**="
 
       <|>
 
-      (\(tk, s) -> MkAugAssign DoubleSlashEq (pyTokenAnn tk) s) <$>
-      token space (\case; TkDoubleSlashEq{} -> True; _ -> False) "//="
+      mkAugAssign DoubleSlashEq (\case; TkDoubleSlashEq{} -> True; _ -> False) "//="
 
     exprOrAssignSt =
       (\a ->
@@ -1005,8 +996,8 @@
              (snd <$> token space (\case; TkDot{} -> True; _ -> False) ".") <*>
              identifier space)
 
-        importAs ws getAnn p =
-          (\a -> ImportAs (getAnn a) a) <$>
+        importAs ws ann p =
+          (\a -> ImportAs (Ann $ ann a) a) <$>
           p <*>
           optional
             ((,) <$>
@@ -1016,7 +1007,7 @@
         importName =
           (\(tk, s) -> Import (pyTokenAnn tk) $ NonEmpty.fromList s) <$>
           token space (\case; TkImport{} -> True; _ -> False) "import" <*>
-          commaSep1 space (importAs space _moduleNameAnn moduleName)
+          commaSep1 space (importAs space (view annot_) moduleName)
 
         dots =
           fmap concat . some $
@@ -1028,29 +1019,33 @@
           token space (\case; TkEllipsis{} -> True; _ -> False) "..."
 
         relativeModuleName =
-          RelativeWithName [] <$> moduleName
+          withSrcInfo $
+          (\b ann -> RelativeWithName (Ann ann) [] b) <$> moduleName
 
           <|>
 
-          (\a -> maybe (Relative $ NonEmpty.fromList a) (RelativeWithName a)) <$>
+          (\a ->
+             maybe
+               (\ann -> Relative (Ann ann) $ NonEmpty.fromList a)
+               (\b ann -> RelativeWithName (Ann ann) a b)) <$>
           dots <*>
           optional moduleName
 
         importTargets =
-          (\(tk, s) -> ImportAll (pyTokenAnn tk) s) <$>
+          (\(tk, s) -> ImportAll (Ann $ pyTokenAnn tk) s) <$>
           star space
 
           <|>
 
-          (\(tk, s) -> ImportSomeParens (pyTokenAnn tk) s) <$>
+          (\(tk, s) -> ImportSomeParens (Ann $ pyTokenAnn tk) s) <$>
           token anySpace (\case; TkLeftParen{} -> True; _ -> False) "(" <*>
-          commaSep1' anySpace (importAs anySpace _identAnn (identifier anySpace)) <*>
+          commaSep1' anySpace (importAs anySpace (view annot_) (identifier anySpace)) <*>
           (snd <$> rightParen space)
 
           <|>
 
-          (\a -> ImportSome (commaSep1Head a ^. importAsAnn) a) <$>
-          commaSep1 space (importAs space _identAnn (identifier space))
+          (\a -> ImportSome (Ann $ commaSep1Head a ^. importAsAnn) a) <$>
+          commaSep1 space (importAs space (view annot_) (identifier space))
 
         importFrom =
           (\(tk, s) -> From (pyTokenAnn tk) s) <$>
@@ -1096,13 +1091,13 @@
 blank :: MonadParsec e PyTokens m => m (Blank SrcInfo)
 blank =
   withSrcInfo $
-  (\b c a -> Blank a b c) <$>
+  (\b c a -> Blank (Ann a) b c) <$>
   some space <*>
   optional comment
 
   <|>
 
-  (\b a -> Blank a [] b) <$> optional comment
+  (\b a -> Blank (Ann a) [] b) <$> optional comment
 
 suite :: MonadParsec e PyTokens m => m (Suite SrcInfo)
 suite =
@@ -1220,8 +1215,8 @@
 upPositional ws =
   (\a ->
     maybe
-      (PositionalParam (_identAnn a) a Nothing)
-      (uncurry $ KeywordParam (_identAnn a) a Nothing)) <$>
+      (PositionalParam (a ^. annot_) a Nothing)
+      (uncurry $ KeywordParam (a ^. annot_) a Nothing)) <$>
   identifier ws <*>
   optional
     ((,) <$>
@@ -1259,8 +1254,8 @@
 tpPositional =
   (\a b ->
     maybe
-      (PositionalParam (_identAnn a) a b)
-      (uncurry $ KeywordParam (_identAnn a) a b)) <$>
+      (PositionalParam (a ^. annot_) a b)
+      (uncurry $ KeywordParam (a ^. annot_) a b)) <$>
   identifier anySpace <*>
   optional tyAnn <*>
   optional
@@ -1292,12 +1287,12 @@
   (do
       e <- exprComp anySpace
       case e of
-        Ident ident -> do
+        Ident ann ident -> do
           eqSpaces <-
             optional $ snd <$> token anySpace (\case; TkEq{} -> True; _ -> False) "="
           case eqSpaces of
-            Nothing -> pure $ PositionalArg (e ^. exprAnn) e
-            Just s -> KeywordArg (e ^. exprAnn) ident s <$> expr anySpace
+            Nothing -> pure $ PositionalArg ann e
+            Just s -> KeywordArg ann ident s <$> expr anySpace
         _ -> pure $ PositionalArg (e ^. exprAnn) e)
 
   <|>
@@ -1334,7 +1329,7 @@
     derefs =
       foldl
         (\b (ws, a) -> Deref (b ^. exprAnn) b ws a)
-        (Ident id1)
+        (Ident (id1 ^. annot_) id1)
         ids
   pure $
     case args of
@@ -1572,4 +1567,4 @@
   ModuleEmpty <$ eof
 
   where
-    tlIndent = level <|> withSrcInfo (pure $ Indents [])
+    tlIndent = level <|> withSrcInfo (pure $ Indents [] . Ann)
diff --git a/src/Language/Python/Internal/Render.hs b/src/Language/Python/Internal/Render.hs
--- a/src/Language/Python/Internal/Render.hs
+++ b/src/Language/Python/Internal/Render.hs
@@ -957,7 +957,7 @@
 renderExpr (Imag _ n ws) = do
   singleton $ TkImag (() <$ n)
   traverse_ renderWhitespace ws
-renderExpr (Ident name) = renderIdent name
+renderExpr (Ident _ name) = renderIdent name
 renderExpr (List _ ws1 exprs ws2) = do
   brackets $ do
     traverse_ renderWhitespace ws1
@@ -1074,13 +1074,13 @@
   traverse_ renderWhitespace ws
 
 renderRelativeModuleName :: RelativeModuleName v a -> RenderOutput ()
-renderRelativeModuleName (RelativeWithName ds mn) = do
+renderRelativeModuleName (RelativeWithName _ ds mn) = do
   traverse_ renderDot ds
   renderModuleName mn
-renderRelativeModuleName (Relative ds) =
+renderRelativeModuleName (Relative _ ds) =
   traverse_ renderDot ds
 
-renderImportAs :: (e a -> RenderOutput ()) -> ImportAs e v a -> RenderOutput ()
+renderImportAs :: (e v a -> RenderOutput ()) -> ImportAs e v a -> RenderOutput ()
 renderImportAs f (ImportAs _ ea m) = do
   f ea
   traverse_
diff --git a/src/Language/Python/Internal/Syntax/IR.hs b/src/Language/Python/Internal/Syntax/IR.hs
--- a/src/Language/Python/Internal/Syntax/IR.hs
+++ b/src/Language/Python/Internal/Syntax/IR.hs
@@ -25,18 +25,18 @@
 import Control.Lens.Lens (Lens', lens)
 import Control.Lens.Prism (Prism')
 import Control.Lens.Review ((#))
-import Control.Lens.Setter ((.~), over, mapped)
+import Control.Lens.Setter (over, mapped)
 import Control.Lens.TH (makeLenses)
 import Control.Lens.Traversal (traverseOf)
 import Control.Lens.Tuple (_1, _2, _3)
 import Data.Bifoldable (bifoldMap)
 import Data.Bifunctor (bimap)
 import Data.Bitraversable (bitraverse)
-import Data.Function ((&))
 import Data.List.NonEmpty (NonEmpty)
 import Data.Monoid ((<>))
 import Data.Validation (Validation(..))
 
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.AugAssign
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Comment
@@ -173,7 +173,7 @@
   | Import
       a
       (NonEmpty Whitespace)
-      (CommaSep1 (ImportAs (ModuleName '[]) '[] a))
+      (CommaSep1 (ImportAs ModuleName '[] a))
   | From
       a
       [Whitespace]
@@ -304,35 +304,35 @@
 
 data Expr a
   = StarExpr
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeStarExprWhitespace :: [Whitespace]
   , _unsafeStarExprValue :: Expr a
   }
   | Unit
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeUnitWhitespaceInner :: [Whitespace]
   , _unsafeUnitWhitespaceRight :: [Whitespace]
   }
   | Lambda
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeLambdaWhitespace :: [Whitespace]
   , _unsafeLambdaArgs :: CommaSep (Param a)
   , _unsafeLambdaColon :: Colon
   , _unsafeLambdaBody :: Expr a
   }
   | Yield
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeYieldWhitespace :: [Whitespace]
   , _unsafeYieldValue :: CommaSep (Expr a)
   }
   | YieldFrom
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeYieldWhitespace :: [Whitespace]
   , _unsafeFromWhitespace :: [Whitespace]
   , _unsafeYieldFromValue :: Expr a
   }
   | Ternary
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- expr
   , _unsafeTernaryValue :: Expr a
   -- 'if' spaces
@@ -345,7 +345,7 @@
   , _unsafeTernaryElse :: Expr a
   }
   | ListComp
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- [ spaces
   , _unsafeListCompWhitespaceLeft :: [Whitespace]
   -- comprehension
@@ -354,7 +354,7 @@
   , _unsafeListCompWhitespaceRight :: [Whitespace]
   }
   | List
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- [ spaces
   , _unsafeListWhitespaceLeft :: [Whitespace]
   -- exprs
@@ -363,7 +363,7 @@
   , _unsafeListWhitespaceRight :: [Whitespace]
   }
   | DictComp
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- { spaces
   , _unsafeDictCompWhitespaceLeft :: [Whitespace]
   -- comprehension
@@ -372,13 +372,13 @@
   , _unsafeDictCompWhitespaceRight :: [Whitespace]
   }
   | Dict
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeDictWhitespaceLeft :: [Whitespace]
   , _unsafeDictValues :: Maybe (CommaSep1' (DictItem a))
   , _unsafeDictWhitespaceRight :: [Whitespace]
   }
   | SetComp
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- { spaces
   , _unsafeSetCompWhitespaceLeft :: [Whitespace]
   -- comprehension
@@ -387,13 +387,13 @@
   , _unsafeSetCompWhitespaceRight :: [Whitespace]
   }
   | Set
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeSetWhitespaceLeft :: [Whitespace]
   , _unsafeSetValues :: CommaSep1' (Expr a)
   , _unsafeSetWhitespaceRight :: [Whitespace]
   }
   | Deref
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- expr
   , _unsafeDerefValueLeft :: Expr a
   -- . spaces
@@ -402,7 +402,7 @@
   , _unsafeDerefValueRight :: Ident '[] a
   }
   | Subscript
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- expr
   , _unsafeSubscriptValueLeft :: Expr a
   -- [ spaces
@@ -413,7 +413,7 @@
   , _unsafeSubscriptWhitespaceRight :: [Whitespace]
   }
   | Call
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- expr
   , _unsafeCallFunction :: Expr a
   -- ( spaces
@@ -424,26 +424,26 @@
   , _unsafeCallWhitespaceRight :: [Whitespace]
   }
   | None
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeNoneWhitespace :: [Whitespace]
   }
   | Ellipsis
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeEllipsisWhitespace :: [Whitespace]
   }
   | BinOp
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeBinOpExprLeft :: Expr a
   , _unsafeBinOpOp :: BinOp a
   , _unsafeBinOpExprRight :: Expr a
   }
   | UnOp
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeUnOpOp :: UnOp a
   , _unsafeUnOpValue :: Expr a
   }
   | Parens
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- ( spaces
   , _unsafeParensWhitespaceLeft :: [Whitespace]
   -- expr
@@ -452,34 +452,35 @@
   , _unsafeParensWhitespaceAfter :: [Whitespace]
   }
   | Ident
-  { _unsafeIdentValue :: Ident '[] a
+  { _exprAnn :: a
+  , _unsafeIdentValue :: Ident '[] a
   }
   | Int
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeIntValue :: IntLiteral a
   , _unsafeIntWhitespace :: [Whitespace]
   }
   | Float
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeFloatValue :: FloatLiteral a
   , _unsafeFloatWhitespace :: [Whitespace]
   }
   | Imag
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeImagValue :: ImagLiteral a
   , _unsafeImagWhitespace :: [Whitespace]
   }
   | Bool
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeBoolValue :: Bool
   , _unsafeBoolWhitespace :: [Whitespace]
   }
   | String
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeStringLiteralValue :: NonEmpty (StringLiteral a)
   }
   | Tuple
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   -- expr
   , _unsafeTupleHead :: Expr a
   -- , spaces
@@ -488,16 +489,16 @@
   , _unsafeTupleTail :: Maybe (CommaSep1' (Expr a))
   }
   | Not
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeNotWhitespace :: [Whitespace]
   , _unsafeNotValue :: Expr a
   }
   | Generator
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _generatorValue :: Comprehension Expr a
   }
   | Await
-  { _unsafeExprAnn :: a
+  { _exprAnn :: a
   , _unsafeAwaitWhitespace :: [Whitespace]
   , _unsafeAwaitValue :: Expr a
   }
@@ -523,7 +524,7 @@
         BinOp a _ _ _ -> a
         UnOp a _ _ -> a
         Parens a _ _ _ -> a
-        Ident a -> a ^. identAnn
+        Ident a _ -> a
         Int a _ _ -> a
         Float a _ _ -> a
         Imag a _ _ -> a
@@ -555,7 +556,7 @@
         BinOp _ a b c -> BinOp ann a b c
         UnOp _ a b -> UnOp ann a b
         Parens _ a b c -> Parens ann a b c
-        Ident a -> Ident $ a & identAnn .~ ann
+        Ident _ b -> Ident ann b
         Int _ a b -> Int ann a b
         Float _ a b -> Float ann a b
         Imag _ a b -> Imag ann a b
@@ -656,71 +657,71 @@
 fromIR_expr ex =
   case ex of
     StarExpr{} -> Failure $ pure (_InvalidUnpacking # (ex ^. exprAnn))
-    Unit a b c -> pure $ Syntax.Unit a b c
+    Unit a b c -> pure $ Syntax.Unit (Ann a) b c
     Lambda a b c d e ->
-      (\c' -> Syntax.Lambda a b c' d) <$>
+      (\c' -> Syntax.Lambda (Ann a) b c' d) <$>
       traverse fromIR_param c <*>
       fromIR_expr e
-    Yield a b c -> Syntax.Yield a b <$> traverse fromIR_expr c
-    YieldFrom a b c d -> Syntax.YieldFrom a b c <$> fromIR_expr d
+    Yield a b c -> Syntax.Yield (Ann a) b <$> traverse fromIR_expr c
+    YieldFrom a b c d -> Syntax.YieldFrom (Ann a) b c <$> fromIR_expr d
     Ternary a b c d e f ->
-      (\b' d' -> Syntax.Ternary a b' c d' e) <$>
+      (\b' d' -> Syntax.Ternary (Ann a) b' c d' e) <$>
       fromIR_expr b <*>
       fromIR_expr d <*>
       fromIR_expr f
     ListComp a b c d ->
-      (\c' -> Syntax.ListComp a b c' d) <$>
+      (\c' -> Syntax.ListComp (Ann a) b c' d) <$>
       fromIR_comprehension fromIR_expr c
     List a b c d ->
-      (\c' -> Syntax.List a b c' d) <$>
+      (\c' -> Syntax.List (Ann a) b c' d) <$>
       traverseOf (traverse.traverse) fromIR_listItem c
     DictComp a b c d ->
-      (\c' -> Syntax.DictComp a b c' d) <$>
+      (\c' -> Syntax.DictComp (Ann a) b c' d) <$>
       fromIR_comprehension fromIR_dictItem c
     Dict a b c d ->
-      (\c' -> Syntax.Dict a b c' d) <$>
+      (\c' -> Syntax.Dict (Ann a) b c' d) <$>
       traverseOf (traverse.traverse) fromIR_dictItem c
     SetComp a b c d ->
-      (\c' -> Syntax.SetComp a b c' d) <$>
+      (\c' -> Syntax.SetComp (Ann a) b c' d) <$>
       fromIR_comprehension fromIR_setItem c
     Set a b c d ->
-      (\c' -> Syntax.Set a b c' d) <$>
+      (\c' -> Syntax.Set (Ann a) b c' d) <$>
       traverse fromIR_setItem c
     Deref a b c d ->
-      (\b' -> Syntax.Deref a b' c d) <$>
+      (\b' -> Syntax.Deref (Ann a) b' c d) <$>
       fromIR_expr b
     Subscript a b c d e ->
-      (\b' d' -> Syntax.Subscript a b' c d' e) <$>
+      (\b' d' -> Syntax.Subscript (Ann a) b' c d' e) <$>
       fromIR_expr b <*>
       traverse fromIR_subscript d
     Call a b c d e ->
-      (\b' d' -> Syntax.Call a b' c d' e) <$>
+      (\b' d' -> Syntax.Call (Ann a) b' c d' e) <$>
       fromIR_expr b <*>
       traverseOf (traverse.traverse) fromIR_arg d
-    None a b -> pure $ Syntax.None a b
-    Ellipsis a b -> pure $ Syntax.Ellipsis a b
+    None a b -> pure $ Syntax.None (Ann a) b
+    Ellipsis a b -> pure $ Syntax.Ellipsis (Ann a) b
     BinOp a b c d ->
-      (\b' d' -> Syntax.BinOp a b' c d') <$>
+      (\b' d' -> Syntax.BinOp (Ann a) b' c d') <$>
       fromIR_expr b <*>
       fromIR_expr d
     UnOp a b c ->
-      Syntax.UnOp a b <$> fromIR_expr c
+      Syntax.UnOp (Ann a) b <$> fromIR_expr c
     Parens a b c d ->
-      (\c' -> Syntax.Parens a b c' d) <$>
+      (\c' -> Syntax.Parens (Ann a) b c' d) <$>
       fromIR_expr c
-    Ident a -> pure $ Syntax.Ident a
-    Int a b c -> pure $ Syntax.Int a b c
-    Float a b c -> pure $ Syntax.Float a b c
-    Imag a b c -> pure $ Syntax.Imag a b c
-    Bool a b c -> pure $ Syntax.Bool a b c
-    String a b -> pure $ Syntax.String a b
+    Ident a b -> pure $ Syntax.Ident (Ann a) b
+    Int a b c -> pure $ Syntax.Int (Ann a) b c
+    Float a b c -> pure $ Syntax.Float (Ann a) b c
+    Imag a b c -> pure $ Syntax.Imag (Ann a) b c
+    Bool a b c -> pure $ Syntax.Bool (Ann a) b c
+    String a b -> pure $ Syntax.String (Ann a) b
     Tuple a b c d ->
-      (\b' -> Syntax.Tuple a b' c) <$>
+      (\b' -> Syntax.Tuple (Ann a) b' c) <$>
       fromIR_tupleItem b <*>
       traverseOf (traverse.traverse) fromIR_tupleItem d
-    Not a b c -> Syntax.Not a b <$> fromIR_expr c
-    Generator a b -> Syntax.Generator a <$> fromIR_comprehension fromIR_expr b
-    Await a b c -> Syntax.Await a b <$> fromIR_expr c
+    Not a b c -> Syntax.Not (Ann a) b <$> fromIR_expr c
+    Generator a b -> Syntax.Generator (Ann a) <$> fromIR_comprehension fromIR_expr b
+    Await a b c -> Syntax.Await (Ann a) b <$> fromIR_expr c
 
 fromIR_suite
   :: AsIRError e a
@@ -729,9 +730,9 @@
 fromIR_suite s =
   case s of
     SuiteOne a b c ->
-      Syntax.SuiteOne a b <$> fromIR_smallStatement c
+      Syntax.SuiteOne (Ann a) b <$> fromIR_smallStatement c
     SuiteMany a b c d e ->
-      Syntax.SuiteMany a b c d <$> fromIR_block e
+      Syntax.SuiteMany (Ann a) b c d <$> fromIR_block e
 
 fromIR_param
   :: AsIRError e a
@@ -740,17 +741,17 @@
 fromIR_param p =
   case p of
     PositionalParam a b c ->
-      Syntax.PositionalParam a b <$> traverseOf (traverse._2) fromIR_expr c
+      Syntax.PositionalParam (Ann a) b <$> traverseOf (traverse._2) fromIR_expr c
     KeywordParam a b c d e ->
-      Syntax.KeywordParam a b <$>
+      Syntax.KeywordParam (Ann a) b <$>
       traverseOf (traverse._2) fromIR_expr c <*>
       pure d <*>
       fromIR_expr e
     StarParam a b c d ->
-      Syntax.StarParam a b c <$> traverseOf (traverse._2) fromIR_expr d
-    UnnamedStarParam a b -> pure $ Syntax.UnnamedStarParam a b
+      Syntax.StarParam (Ann a) b c <$> traverseOf (traverse._2) fromIR_expr d
+    UnnamedStarParam a b -> pure $ Syntax.UnnamedStarParam (Ann a) b
     DoubleStarParam a b c d ->
-      Syntax.DoubleStarParam a b c <$> traverseOf (traverse._2) fromIR_expr d
+      Syntax.DoubleStarParam (Ann a) b c <$> traverseOf (traverse._2) fromIR_expr d
 
 fromIR_arg
   :: AsIRError e a
@@ -758,17 +759,17 @@
   -> Validation (NonEmpty e) (Syntax.Arg '[] a)
 fromIR_arg a =
   case a of
-    PositionalArg a b -> Syntax.PositionalArg a <$> fromIR_expr b
-    KeywordArg a b c d -> Syntax.KeywordArg a b c <$> fromIR_expr d
-    StarArg a b c -> Syntax.StarArg a b <$> fromIR_expr c
-    DoubleStarArg a b c -> Syntax.DoubleStarArg a b <$> fromIR_expr c
+    PositionalArg a b -> Syntax.PositionalArg (Ann a) <$> fromIR_expr b
+    KeywordArg a b c d -> Syntax.KeywordArg (Ann a) b c <$> fromIR_expr d
+    StarArg a b c -> Syntax.StarArg (Ann a) b <$> fromIR_expr c
+    DoubleStarArg a b c -> Syntax.DoubleStarArg (Ann a) b <$> fromIR_expr c
 
 fromIR_decorator
   :: AsIRError e a
   => Decorator a
   -> Validation (NonEmpty e) (Syntax.Decorator '[] a)
 fromIR_decorator (Decorator a b c d e f g) =
-  (\d' -> Syntax.Decorator a b c d' e f g) <$>
+  (\d' -> Syntax.Decorator (Ann a) b c d' e f g) <$>
   fromIR_expr d
 
 fromIR_exceptAs
@@ -776,7 +777,7 @@
   => ExceptAs a
   -> Validation (NonEmpty e) (Syntax.ExceptAs '[] a)
 fromIR_exceptAs (ExceptAs a b c) =
-  (\b' -> Syntax.ExceptAs a b' c) <$>
+  (\b' -> Syntax.ExceptAs (Ann a) b' c) <$>
   fromIR_expr b
 
 fromIR_withItem
@@ -784,7 +785,7 @@
   => WithItem a
   -> Validation (NonEmpty e) (Syntax.WithItem '[] a)
 fromIR_withItem (WithItem a b c) =
-  Syntax.WithItem a <$>
+  Syntax.WithItem (Ann a) <$>
   fromIR_expr b <*>
   traverseOf (traverse._2) fromIR_expr c
 
@@ -794,7 +795,7 @@
   -> Comprehension ex a
   -> Validation (NonEmpty e) (Syntax.Comprehension ex' '[] a)
 fromIR_comprehension f (Comprehension a b c d) =
-  Syntax.Comprehension a <$>
+  Syntax.Comprehension (Ann a) <$>
   f b <*>
   fromIR_compFor c <*>
   traverse (bitraverse fromIR_compFor fromIR_compIf) d
@@ -806,11 +807,11 @@
 fromIR_dictItem di =
   case di of
     DictItem a b c d ->
-      (\b' -> Syntax.DictItem a b' c) <$>
+      (\b' -> Syntax.DictItem (Ann a) b' c) <$>
       fromIR_expr b <*>
       fromIR_expr d
     DictUnpack a b c ->
-      Syntax.DictUnpack a b <$> fromIR_expr c
+      Syntax.DictUnpack (Ann a) b <$> fromIR_expr c
 
 fromIR_subscript
   :: AsIRError e a
@@ -839,7 +840,7 @@
   => CompFor a
   -> Validation (NonEmpty e) (Syntax.CompFor '[] a)
 fromIR_compFor (CompFor a b c d e) =
-  (\c' -> Syntax.CompFor a b c' d) <$>
+  (\c' -> Syntax.CompFor (Ann a) b c' d) <$>
   fromIR_expr c <*>
   fromIR_expr e
 
@@ -848,7 +849,7 @@
   => CompIf a
   -> Validation (NonEmpty e) (Syntax.CompIf '[] a)
 fromIR_compIf (CompIf a b c) =
-  Syntax.CompIf a b <$> fromIR_expr c
+  Syntax.CompIf (Ann a) b <$> fromIR_expr c
 
 fromIR_smallStatement
   :: AsIRError e a
@@ -877,32 +878,32 @@
 fromIR_SimpleStatement ex =
   case ex of
     Assign a b c ->
-      Syntax.Assign a <$>
+      Syntax.Assign (Ann a) <$>
       fromIR_expr b <*>
       traverseOf (traverse._2) fromIR_expr c
-    Return a b c -> Syntax.Return a b <$> traverse fromIR_expr c
-    Expr a b -> Syntax.Expr a <$> fromIR_expr b
+    Return a b c -> Syntax.Return (Ann a) b <$> traverse fromIR_expr c
+    Expr a b -> Syntax.Expr (Ann a) <$> fromIR_expr b
     AugAssign a b c d ->
-      (\b' d' -> Syntax.AugAssign a b' c d') <$>
+      (\b' d' -> Syntax.AugAssign (Ann a) b' c d') <$>
       fromIR_expr b <*>
       fromIR_expr d
-    Pass a ws -> pure $ Syntax.Pass a ws
-    Break a ws -> pure $ Syntax.Break a ws
-    Continue a ws -> pure $ Syntax.Continue a ws
-    Global a b c -> pure $ Syntax.Global a b c
-    Nonlocal a b c -> pure $ Syntax.Nonlocal a b c
-    Del a b c -> Syntax.Del a b <$> traverse fromIR_expr c
-    Import a b c -> pure $ Syntax.Import a b c
-    From a b c d e -> pure $ Syntax.From a b c d e
+    Pass a ws -> pure $ Syntax.Pass (Ann a) ws
+    Break a ws -> pure $ Syntax.Break (Ann a) ws
+    Continue a ws -> pure $ Syntax.Continue (Ann a) ws
+    Global a b c -> pure $ Syntax.Global (Ann a) b c
+    Nonlocal a b c -> pure $ Syntax.Nonlocal (Ann a) b c
+    Del a b c -> Syntax.Del (Ann a) b <$> traverse fromIR_expr c
+    Import a b c -> pure $ Syntax.Import (Ann a) b c
+    From a b c d e -> pure $ Syntax.From (Ann a) b c d e
     Raise a b c ->
-      Syntax.Raise a b <$>
+      Syntax.Raise (Ann a) b <$>
       traverse
         (\(a, b) -> (,) <$>
           fromIR_expr a <*>
           traverseOf (traverse._2) fromIR_expr b)
         c
     Assert a b c d ->
-      Syntax.Assert a b <$>
+      Syntax.Assert (Ann a) b <$>
       fromIR_expr c <*>
       traverseOf (traverse._2) fromIR_expr d
 
@@ -913,24 +914,24 @@
 fromIR_compoundStatement st =
   case st of
     Fundef a b asyncWs c d e f g h i j ->
-      (\b' g' i' -> Syntax.Fundef a b' asyncWs c d e f g' h i') <$>
+      (\b' g' i' -> Syntax.Fundef (Ann a) b' asyncWs c d e f g' h i') <$>
       traverse fromIR_decorator b <*>
       traverse fromIR_param g <*>
       traverseOf (traverse._2) fromIR_expr i <*>
       fromIR_suite j
     If a b c d e f g ->
-      Syntax.If a b c <$>
+      Syntax.If (Ann a) b c <$>
       fromIR_expr d <*>
       fromIR_suite e <*>
       traverse (\(a, b, c, d) -> (,,,) a b <$> fromIR_expr c <*> fromIR_suite d) f <*>
       traverseOf (traverse._3) fromIR_suite g
     While a b c d e f ->
-      Syntax.While a b c <$>
+      Syntax.While (Ann a) b c <$>
       fromIR_expr d <*>
       fromIR_suite e <*>
       traverseOf (traverse._3) fromIR_suite f
     TryExcept a b c d e f g ->
-      Syntax.TryExcept a b c <$>
+      Syntax.TryExcept (Ann a) b c <$>
       fromIR_suite d <*>
       traverse
         (\(a, b, c, d) -> (,,,) a b <$> traverse fromIR_exceptAs c <*> fromIR_suite d)
@@ -938,20 +939,20 @@
       traverseOf (traverse._3) fromIR_suite f <*>
       traverseOf (traverse._3) fromIR_suite g
     TryFinally a b c d e f g ->
-      (\d' -> Syntax.TryFinally a b c d' e f) <$> fromIR_suite d <*> fromIR_suite g
+      (\d' -> Syntax.TryFinally (Ann a) b c d' e f) <$> fromIR_suite d <*> fromIR_suite g
     For a b asyncWs c d e f g h ->
-      (\d' -> Syntax.For a b asyncWs c d' e) <$>
+      (\d' -> Syntax.For (Ann a) b asyncWs c d' e) <$>
       fromIR_expr d <*>
       traverse fromIR_expr f <*>
       fromIR_suite g <*>
       traverseOf (traverse._3) fromIR_suite h
     ClassDef a b c d e f g ->
-      (\b' -> Syntax.ClassDef a b' c d e) <$>
+      (\b' -> Syntax.ClassDef (Ann a) b' c d e) <$>
       traverse fromIR_decorator b <*>
       traverseOf (traverse._2.traverse.traverse) fromIR_arg f <*>
       fromIR_suite g
     With a b asyncWs c d e ->
-      Syntax.With a b asyncWs c <$>
+      Syntax.With (Ann a) b asyncWs c <$>
       traverse fromIR_withItem d <*>
       fromIR_suite e
 
@@ -960,40 +961,40 @@
   => Expr a
   -> Validation (NonEmpty e) (Syntax.ListItem '[] a)
 fromIR_listItem (StarExpr a b c) =
-  Syntax.ListUnpack a [] b <$> fromIR_expr c
+  Syntax.ListUnpack (Ann a) [] b <$> fromIR_expr c
 fromIR_listItem (Parens a b c d) =
   (\case
       Syntax.ListUnpack w x y z -> Syntax.ListUnpack w ((b, d) : x) y z
-      Syntax.ListItem x y -> Syntax.ListItem a (Syntax.Parens x b y d)) <$>
+      Syntax.ListItem x y -> Syntax.ListItem (Ann a) (Syntax.Parens x b y d)) <$>
   fromIR_listItem c
-fromIR_listItem e = (\x -> Syntax.ListItem (x ^. Syntax.exprAnn) x) <$> fromIR_expr e
+fromIR_listItem e = (\x -> Syntax.ListItem (x ^. annot) x) <$> fromIR_expr e
 
 fromIR_tupleItem
   :: AsIRError e a
   => Expr a
   -> Validation (NonEmpty e) (Syntax.TupleItem '[] a)
 fromIR_tupleItem (StarExpr a b c) =
-  Syntax.TupleUnpack a [] b <$> fromIR_expr c
+  Syntax.TupleUnpack (Ann a) [] b <$> fromIR_expr c
 fromIR_tupleItem (Parens a b c d) =
   (\case
       Syntax.TupleUnpack w x y z -> Syntax.TupleUnpack w ((b, d) : x) y z
-      Syntax.TupleItem x y -> Syntax.TupleItem a (Syntax.Parens x b y d)) <$>
+      Syntax.TupleItem x y -> Syntax.TupleItem (Ann a) (Syntax.Parens x b y d)) <$>
   fromIR_tupleItem c
 fromIR_tupleItem e =
-  (\x -> Syntax.TupleItem (x ^. Syntax.exprAnn) x) <$> fromIR_expr e
+  (\x -> Syntax.TupleItem (x ^. annot) x) <$> fromIR_expr e
 
 fromIR_setItem
   :: AsIRError e a
   => Expr a
   -> Validation (NonEmpty e) (Syntax.SetItem '[] a)
 fromIR_setItem (StarExpr a b c) =
-  Syntax.SetUnpack a [] b <$> fromIR_expr c
+  Syntax.SetUnpack (Ann a) [] b <$> fromIR_expr c
 fromIR_setItem (Parens a b c d) =
   (\case
       Syntax.SetUnpack w x y z -> Syntax.SetUnpack w ((b, d) : x) y z
-      Syntax.SetItem x y -> Syntax.SetItem a (Syntax.Parens x b y d)) <$>
+      Syntax.SetItem x y -> Syntax.SetItem (Ann a) (Syntax.Parens x b y d)) <$>
   fromIR_setItem c
-fromIR_setItem e = (\x -> Syntax.SetItem (x ^. Syntax.exprAnn) x) <$> fromIR_expr e
+fromIR_setItem e = (\x -> Syntax.SetItem (x ^. annot) x) <$> fromIR_expr e
 
 fromIR
   :: AsIRError e a
diff --git a/src/Language/Python/Internal/Token.hs b/src/Language/Python/Internal/Token.hs
--- a/src/Language/Python/Internal/Token.hs
+++ b/src/Language/Python/Internal/Token.hs
@@ -13,9 +13,11 @@
 
 module Language.Python.Internal.Token where
 
+import Control.Lens.Getter ((^.))
 import Data.Deriving (deriveEq1, deriveOrd1)
 import Data.Functor.Classes (liftCompare, liftEq)
 
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Comment (Comment(..))
 import Language.Python.Syntax.Numbers
 import Language.Python.Syntax.Strings
@@ -177,9 +179,9 @@
     TkElif a -> a
     TkWhile a -> a
     TkAssert a -> a
-    TkInt a -> _intLiteralAnn a
-    TkFloat a -> _floatLiteralAnn a
-    TkImag a -> _imagLiteralAnn a
+    TkInt a -> a ^. annot_
+    TkFloat a -> a ^. annot_
+    TkImag a -> a ^. annot_
     TkIdent _ a -> a
     TkString _ _ _ _ a -> a
     TkBytes _ _ _ _ a -> a
@@ -206,7 +208,7 @@
     TkSemicolon a -> a
     TkComma a -> a
     TkDot a -> a
-    TkComment a -> _commentAnn a
+    TkComment a -> a ^. annot_
     TkStar a -> a
     TkDoubleStar a -> a
     TkSlash a -> a
diff --git a/src/Language/Python/Optics.hs b/src/Language/Python/Optics.hs
--- a/src/Language/Python/Optics.hs
+++ b/src/Language/Python/Optics.hs
@@ -20,6 +20,8 @@
 
 module Language.Python.Optics
   ( module Language.Python.Optics.Validated
+    -- * Identifiers
+  , module Language.Python.Optics.Idents
     -- * Indentation
   , module Language.Python.Optics.Indents
     -- * Newlines
@@ -75,11 +77,13 @@
 import Control.Lens.Getter ((^.), view)
 import Control.Lens.Iso (Iso', iso, from)
 import Control.Lens.Traversal (Traversal)
-import Control.Lens.Prism (Prism, prism)
+import Control.Lens.Prism (Choice, Prism, prism)
 
+import Language.Python.Optics.Idents
 import Language.Python.Optics.Indents
 import Language.Python.Optics.Newlines
 import Language.Python.Optics.Validated
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Expr
 import Language.Python.Syntax.Ident
 import Language.Python.Syntax.Statement
@@ -375,12 +379,21 @@
 instance HasWith Statement where
   _With = _CompoundStatement._With
 
-_Ident :: Prism (Expr v a) (Expr '[] a) (Ident v a) (Ident '[] a)
+-- |
+-- A faux-Prism for matching on the @Ident@ constructor of an 'Expr'.
+--
+-- It's not a Prism because:
+--
+-- When 'Control.Lens.Fold.preview'ing, it discards the 'Expr'\'s annotation, and when
+-- 'Control.Lens.Review.review'ing, it re-constructs an annotation from the supplied 'Language.Python.Syntax.Ident.Ident'
+--
+-- @'_Ident' :: 'Prism' ('Expr' v a) ('Expr' '[] a) ('Ident' v a) ('Ident' '[] a)@
+_Ident :: (Choice p, Applicative f) => p (Ident v a) (f (Ident '[] a)) -> p (Expr v a) (f (Expr '[] a))
 _Ident =
   prism
-    Ident
+    (\i -> Ident (i ^. annot) i)
     (\case
-        Ident a -> Right a
+        Ident _ a -> Right a
         a -> Left $ a ^. unvalidated)
 
 -- | 'Traversal' targeting the variables that would modified as a result of an assignment
@@ -421,7 +434,7 @@
   case e of
     List a b c d -> (\c' -> List a b c' d) <$> (traverse.traverse._Exprs.assignTargets) f c
     Parens a b c d -> (\c' -> Parens a b c' d) <$> assignTargets f c
-    Ident a -> Ident <$> f a
+    Ident a b -> Ident a <$> f b
     Tuple a b c d ->
       (\b' d' -> Tuple a b' c d') <$>
       (_Exprs.assignTargets) f b <*>
diff --git a/src/Language/Python/Optics/Idents.hs b/src/Language/Python/Optics/Idents.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/Python/Optics/Idents.hs
@@ -0,0 +1,162 @@
+{-# language BangPatterns #-}
+{-# language DataKinds #-}
+{-# language DefaultSignatures #-}
+{-# language FlexibleContexts #-}
+{-# language FlexibleInstances #-}
+{-# language MultiParamTypeClasses #-}
+{-# language TypeFamilies #-}
+{-# language TypeOperators #-}
+{-# language ScopedTypeVariables, TypeApplications #-}
+
+{-|
+Module      : Language.Python.Optics.Idents
+Copyright   : (C) CSIRO 2017-2019
+License     : BSD3
+Maintainer  : Isaac Elliott <isaace71295@gmail.com>
+Stability   : experimental
+Portability : non-portable
+-}
+
+module Language.Python.Optics.Idents (HasIdents(..)) where
+
+import Control.Lens.Iso (iso)
+import Control.Lens.Traversal (Traversal)
+import Data.List.NonEmpty (NonEmpty)
+import GHC.Generics
+
+import Language.Python.Syntax.Ann
+import Language.Python.Syntax.AugAssign
+import Language.Python.Syntax.CommaSep
+import Language.Python.Syntax.Comment
+import Language.Python.Syntax.Expr
+import Language.Python.Syntax.Ident
+import Language.Python.Syntax.Import
+import Language.Python.Syntax.Module
+import Language.Python.Syntax.ModuleNames
+import Language.Python.Syntax.Numbers
+import Language.Python.Syntax.Operator.Binary
+import Language.Python.Syntax.Operator.Unary
+import Language.Python.Syntax.Punctuation
+import Language.Python.Syntax.Statement
+import Language.Python.Syntax.Strings
+import Language.Python.Syntax.Whitespace
+
+-- | 'Traversal' that targets all the 'Ident's in a structure
+class HasIdents s where
+  _Idents :: Traversal (s v a) (s '[] a) (Ident v a) (Ident '[] a)
+  default _Idents
+    :: forall v a l m
+    . ( Generic (s v a)
+      , Generic (s '[] a)
+      , Rep (s v a) ~ l
+      , Rep (s '[] a) ~ m
+      , GHasIdents l m v a
+      )
+    => Traversal (s v a) (s '[] a) (Ident v a) (Ident '[] a)
+  _Idents = iso from to . gidents @l @m @v @a
+
+class HasIdents' s t v a where
+  _Idents' :: Traversal s t (Ident v a) (Ident '[] a)
+
+instance HasIdents s => HasIdents' (s v a) (s '[] a) v a where
+  _Idents' = _Idents
+
+instance HasIdents CompFor
+instance HasIdents CompIf
+instance HasIdents DictItem
+instance HasIdents SetItem
+instance HasIdents e => HasIdents (Comprehension e)
+instance HasIdents TupleItem
+instance HasIdents ListItem
+instance HasIdents Param
+instance HasIdents Subscript
+instance HasIdents Arg
+instance HasIdents Ident where
+  _Idents = id
+instance HasIdents n => HasIdents (ImportAs n)
+instance HasIdents Expr
+instance HasIdents ImportTargets
+instance HasIdents RelativeModuleName
+instance HasIdents ModuleName
+instance HasIdents SimpleStatement
+instance HasIdents SmallStatement
+instance HasIdents Decorator
+instance HasIdents Block
+instance HasIdents Suite
+instance HasIdents ExceptAs
+instance HasIdents WithItem
+instance HasIdents CompoundStatement
+instance HasIdents Statement
+instance HasIdents Module
+
+class GHasIdents s t v a where
+  gidents :: Traversal (s x) (t x) (Ident v a) (Ident '[] a)
+
+instance (GHasIdents a c v x, GHasIdents b d v x) => GHasIdents (a :+: b) (c :+: d) v x where
+  gidents f (L1 a) = L1 <$> gidents f a
+  gidents f (R1 a) = R1 <$> gidents f a
+
+instance (GHasIdents a c v x, GHasIdents b d v x) => GHasIdents (a :*: b) (c :*: d) v x where
+  gidents f (a :*: b) = (:*:) <$> gidents f a <*> gidents f b
+
+instance GHasIdents U1 U1 v x where
+  gidents _ U1 = pure U1
+
+instance GHasIdents V1 V1 v x where
+  gidents _ !_ = undefined
+
+instance GHasIdents a b v x => GHasIdents (M1 i t a) (M1 i' t' b) v x where
+  gidents f (M1 a) = M1 <$> gidents f a
+
+instance {-# overlapping #-} HasIdents s => GHasIdents (K1 i (s v a)) (K1 i (s '[] a)) v a where
+  gidents f (K1 a) = K1 <$> _Idents f a
+
+instance {-# overlappable #-} HasIdents' a b v x => GHasIdents (K1 i a) (K1 i b) v x where
+  gidents f (K1 a) = K1 <$> _Idents' f a
+
+-- redundant instances
+
+instance HasIdents' (Ann a) (Ann a) v a where; _Idents' _ = pure
+instance HasIdents' (BinOp a) (BinOp a) v a where; _Idents' _ = pure
+instance HasIdents' (IntLiteral a) (IntLiteral a) v a where; _Idents' _ = pure
+instance HasIdents' (FloatLiteral a) (FloatLiteral a) v a where; _Idents' _ = pure
+instance HasIdents' (ImagLiteral a) (ImagLiteral a) v a where; _Idents' _ = pure
+instance HasIdents' (StringLiteral a) (StringLiteral a) v a where; _Idents' _ = pure
+instance HasIdents' (UnOp a) (UnOp a) v a where; _Idents' _ = pure
+instance HasIdents' (AugAssign a) (AugAssign a) v a where; _Idents' _ = pure
+instance HasIdents' Whitespace Whitespace v a where; _Idents' _ = pure
+instance HasIdents' Newline Newline v a where; _Idents' _ = pure
+instance HasIdents' (Blank a) (Blank a) v a where; _Idents' _ = pure
+instance HasIdents' Colon Colon v a where; _Idents' _ = pure
+instance HasIdents' At At v a where; _Idents' _ = pure
+instance HasIdents' (Semicolon a) (Semicolon a) v a where; _Idents' _ = pure
+instance HasIdents' (Comment a) (Comment a) v a where; _Idents' _ = pure
+instance HasIdents' (Indents a) (Indents a) v a where; _Idents' _ = pure
+instance HasIdents' Dot Dot v a where; _Idents' _ = pure
+instance HasIdents' Equals Equals v a where; _Idents' _ = pure
+instance HasIdents' Comma Comma v a where; _Idents' _ = pure
+instance HasIdents' Bool Bool v a where; _Idents' _ = pure
+instance HasIdents' a b v x => HasIdents' [a] [b] v x where; _Idents' = traverse._Idents'
+instance HasIdents' a b v x => HasIdents' (NonEmpty a) (NonEmpty b) v x where; _Idents' = traverse._Idents'
+instance HasIdents' a b v x => HasIdents' (Maybe a) (Maybe b) v x where; _Idents' = traverse._Idents'
+instance HasIdents' a b v x => HasIdents' (CommaSep a) (CommaSep b) v x where; _Idents' = traverse._Idents'
+instance HasIdents' a b v x => HasIdents' (CommaSep1 a) (CommaSep1 b) v x where; _Idents' = traverse._Idents'
+instance HasIdents' a b v x => HasIdents' (CommaSep1' a) (CommaSep1' b) v x where; _Idents' = traverse._Idents'
+instance (HasIdents' a b v x, HasIdents' c d v x) => HasIdents' (a, c) (b, d) v x where
+  _Idents' f (a, b) = (,) <$> _Idents' f a <*> _Idents' f b
+instance (HasIdents' a b v x, HasIdents' c d v x, HasIdents' e f v x) => HasIdents' (a, c, e) (b, d, f) v x where
+  _Idents' f (a, b, c) =
+    (,,) <$>
+    _Idents' f a <*>
+    _Idents' f b <*>
+    _Idents' f c
+instance (HasIdents' a b v x, HasIdents' c d v x, HasIdents' e f v x, HasIdents' g h v x) => HasIdents' (a, c, e, g) (b, d, f, h) v x where
+  _Idents' f (a, b, c, d) =
+    (,,,) <$>
+    _Idents' f a <*>
+    _Idents' f b <*>
+    _Idents' f c <*>
+    _Idents' f d
+instance (HasIdents' a b v x, HasIdents' c d v x) => HasIdents' (Either a c) (Either b d) v x where
+  _Idents' f (Left a) = Left <$> _Idents' f a
+  _Idents' f (Right a) = Right <$>_Idents' f a
diff --git a/src/Language/Python/Optics/Newlines.hs b/src/Language/Python/Optics/Newlines.hs
--- a/src/Language/Python/Optics/Newlines.hs
+++ b/src/Language/Python/Optics/Newlines.hs
@@ -46,18 +46,18 @@
     _Newlines f c <*>
     _Newlines f d
 
-instance HasNewlines (e a) => HasNewlines (ImportAs e v a) where
+instance HasNewlines (e v a) => HasNewlines (ImportAs e v a) where
   _Newlines f (ImportAs a b c) =
     ImportAs a <$>
     _Newlines f b <*>
     _Newlines f c
 
 instance HasNewlines (RelativeModuleName v a) where
-  _Newlines f (RelativeWithName a b) =
-    RelativeWithName <$>
+  _Newlines f (RelativeWithName ann a b) =
+    RelativeWithName ann <$>
     _Newlines f a <*>
     _Newlines f b
-  _Newlines f (Relative a) = Relative <$> _Newlines f a
+  _Newlines f (Relative ann a) = Relative ann <$> _Newlines f a
 
 instance (HasNewlines a, HasNewlines b) => HasNewlines (Either a b) where
   _Newlines f (Left a) = Left <$> _Newlines f a
@@ -389,7 +389,7 @@
             _Newlines fun b <*>
             go c <*>
             _Newlines fun d
-          Ident a -> Ident <$> _Newlines fun a
+          Ident a b -> Ident a <$> _Newlines fun b
           Int a b c -> Int a b <$> _Newlines fun c
           Float a b c -> Float a b <$> _Newlines fun c
           Imag a b c -> Imag a b <$> _Newlines fun c
diff --git a/src/Language/Python/Parse.hs b/src/Language/Python/Parse.hs
--- a/src/Language/Python/Parse.hs
+++ b/src/Language/Python/Parse.hs
@@ -12,12 +12,19 @@
 -}
 
 module Language.Python.Parse
-  ( module Language.Python.Parse.Error
+  ( module Data.Validation
+  , module Language.Python.Parse.Error
   , Parser
+    -- * Parsing some 'Text'
   , parseModule
   , parseStatement
   , parseExpr
   , parseExprList
+    -- * Parsing from a file
+  , readModule
+  , readStatement
+  , readExpr
+  , readExprList
     -- * Source Information
   , SrcInfo(..), initialSrcInfo
   )
@@ -27,9 +34,11 @@
 import Data.Bifunctor (first)
 import Data.List.NonEmpty (NonEmpty)
 import Data.Text (Text)
-import Data.Validation (Validation, bindValidation, fromEither)
+import Data.Validation
 import Text.Megaparsec (eof)
 
+import qualified Data.Text.IO as Text
+
 import Language.Python.Internal.Lexer
   ( SrcInfo(..), initialSrcInfo, withSrcInfo
   , tokenize, insertTabs
@@ -41,6 +50,7 @@
   )
 import Language.Python.Internal.Syntax.IR (AsIRError)
 import Language.Python.Parse.Error
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Expr (Expr)
 import Language.Python.Syntax.Module (Module)
 import Language.Python.Syntax.Statement (Statement)
@@ -94,7 +104,7 @@
   in
     fromEither (first pure ir) `bindValidation` IR.fromIR_statement
   where
-    tlIndent = level <|> withSrcInfo (pure $ Indents [])
+    tlIndent = level <|> withSrcInfo (pure $ Indents [] . Ann)
 
 -- | Parse an expression list (unparenthesised tuple)
 --
@@ -141,3 +151,59 @@
       runParser fp (expr space <* eof) tabbed
   in
     fromEither (first pure ir) `bindValidation` IR.fromIR_expr
+
+-- | Parse a module from a file
+--
+-- https://docs.python.org/3/reference/toplevel_components.html#file-input
+readModule
+  :: ( AsLexicalError e Char
+     , AsTabError e SrcInfo
+     , AsIncorrectDedent e SrcInfo
+     , AsParseError e (PyToken SrcInfo)
+     , AsIRError e SrcInfo
+     )
+  => FilePath -- ^ File to read
+  -> IO (Validation (NonEmpty e) (Module '[] SrcInfo))
+readModule fp = parseModule fp <$> Text.readFile fp
+
+-- | Parse a statement from a file
+--
+-- https://docs.python.org/3/reference/compound_stmts.html#grammar-token-statement
+readStatement
+  :: ( AsLexicalError e Char
+     , AsTabError e SrcInfo
+     , AsIncorrectDedent e SrcInfo
+     , AsParseError e (PyToken SrcInfo)
+     , AsIRError e SrcInfo
+     )
+  => FilePath -- ^ File to read
+  -> IO (Validation (NonEmpty e) (Statement '[] SrcInfo))
+readStatement fp = parseStatement fp <$> Text.readFile fp
+
+-- | Parse an expression from a file
+--
+-- https://docs.python.org/3.5/reference/expressions.html#grammar-token-expression
+readExpr
+  :: ( AsLexicalError e Char
+     , AsTabError e SrcInfo
+     , AsIncorrectDedent e SrcInfo
+     , AsParseError e (PyToken SrcInfo)
+     , AsIRError e SrcInfo
+     )
+  => FilePath -- ^ File to read
+  -> IO (Validation (NonEmpty e) (Expr '[] SrcInfo))
+readExpr fp = parseExpr fp <$> Text.readFile fp
+
+-- | Parse an expression list (unparenthesised tuple) from a file
+--
+-- https://docs.python.org/3.5/reference/expressions.html#grammar-token-expression_list
+readExprList
+  :: ( AsLexicalError e Char
+     , AsTabError e SrcInfo
+     , AsIncorrectDedent e SrcInfo
+     , AsParseError e (PyToken SrcInfo)
+     , AsIRError e SrcInfo
+     )
+  => FilePath -- ^ File to read
+  -> IO (Validation (NonEmpty e) (Expr '[] SrcInfo))
+readExprList fp = parseExprList fp <$> Text.readFile fp
diff --git a/src/Language/Python/Syntax.hs b/src/Language/Python/Syntax.hs
--- a/src/Language/Python/Syntax.hs
+++ b/src/Language/Python/Syntax.hs
@@ -12,7 +12,8 @@
 -}
 
 module Language.Python.Syntax
-  ( module Language.Python.Syntax.AugAssign
+  ( module Language.Python.Syntax.Ann
+  , module Language.Python.Syntax.AugAssign
   , module Language.Python.Syntax.CommaSep
   , module Language.Python.Syntax.Comment
   , module Language.Python.Syntax.Expr
@@ -31,6 +32,7 @@
   )
 where
 
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.AugAssign
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Comment
diff --git a/src/Language/Python/Syntax/Ann.hs b/src/Language/Python/Syntax/Ann.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/Python/Syntax/Ann.hs
@@ -0,0 +1,44 @@
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language GeneralizedNewtypeDeriving #-}
+{-# language ScopedTypeVariables, TypeApplications #-}
+{-# language FlexibleInstances, MultiParamTypeClasses, TemplateHaskell, TypeFamilies #-}
+
+{-|
+Module      : Language.Python.Syntax.Ann
+Copyright   : (C) CSIRO 2017-2019
+License     : BSD3
+Maintainer  : Isaac Elliott <isaace71295@gmail.com>
+Stability   : experimental
+Portability : non-portable
+-}
+
+module Language.Python.Syntax.Ann
+  ( Ann(..)
+  , annot_
+  , HasAnn(..)
+  )
+where
+
+import Control.Lens.Lens (Lens')
+import Control.Lens.TH (makeWrapped)
+import Control.Lens.Wrapped (_Wrapped)
+import Data.Deriving (deriveEq1, deriveOrd1, deriveShow1)
+import Data.Semigroup (Semigroup)
+import Data.Monoid (Monoid)
+
+-- | Used to mark annotations in data structures, which helps with generic deriving
+newtype Ann a = Ann { getAnn :: a }
+  deriving (Eq, Ord, Show, Functor, Foldable, Traversable, Semigroup, Monoid)
+
+-- | Classy 'Lens'' for things that are annotated
+class HasAnn s where
+  annot :: Lens' (s a) (Ann a)
+
+-- | Get an annotation and forget the wrapper
+annot_ :: HasAnn s => Lens' (s a) a
+annot_ = annot._Wrapped
+
+makeWrapped ''Ann
+deriveEq1 ''Ann
+deriveOrd1 ''Ann
+deriveShow1 ''Ann
diff --git a/src/Language/Python/Syntax/AugAssign.hs b/src/Language/Python/Syntax/AugAssign.hs
--- a/src/Language/Python/Syntax/AugAssign.hs
+++ b/src/Language/Python/Syntax/AugAssign.hs
@@ -1,4 +1,5 @@
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 
 {-|
 Module      : Language.Python.Syntax.AugAssign
@@ -11,8 +12,11 @@
 
 module Language.Python.Syntax.AugAssign where
 
-import Control.Lens.Lens (lens)
+import Control.Lens.Lens (Lens', lens)
+import Data.Generics.Product.Typed (typed)
+import GHC.Generics
 
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Whitespace
 
 -- | Augmented assignments (PEP 203), such as:
@@ -31,11 +35,15 @@
 -- optional annotation, which can simply be @()@ if no annotation is desired.
 data AugAssign a
   = MkAugAssign
-  { _augAssignType :: AugAssignOp
-  , _augAssignAnn :: a
+  { _augAssignAnn :: Ann a
+  , _augAssignType :: AugAssignOp
   , _augAssignWhitespace :: [Whitespace]
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
+
+instance HasAnn AugAssign where
+  annot :: forall a. Lens' (AugAssign a) (Ann a)
+  annot = typed @(Ann a)
 
 instance HasTrailingWhitespace (AugAssign a) where
   trailingWhitespace =
diff --git a/src/Language/Python/Syntax/CommaSep.hs b/src/Language/Python/Syntax/CommaSep.hs
--- a/src/Language/Python/Syntax/CommaSep.hs
+++ b/src/Language/Python/Syntax/CommaSep.hs
@@ -1,5 +1,5 @@
 {-# language LambdaCase #-}
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
 
 {-|
 Module      : Language.Python.Syntax.CommaSep
@@ -32,6 +32,7 @@
 import Data.List.NonEmpty (NonEmpty(..))
 import Data.Maybe (fromMaybe)
 import Data.Semigroup (Semigroup(..))
+import GHC.Generics (Generic)
 
 import Language.Python.Syntax.Punctuation
 import Language.Python.Syntax.Whitespace (Whitespace (Space), HasTrailingWhitespace (..))
@@ -41,7 +42,7 @@
   = CommaSepNone
   | CommaSepOne a
   | CommaSepMany a Comma (CommaSep a)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
 -- | 'Traversal' targeting the trailing whitespace in a comma separated list.
 --
@@ -91,7 +92,7 @@
 data CommaSep1 a
   = CommaSepOne1 a
   | CommaSepMany1 a Comma (CommaSep1 a)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
 -- | Get the first element of a 'CommaSep1'
 commaSep1Head :: CommaSep1 a -> a
@@ -139,7 +140,7 @@
 data CommaSep1' a
   = CommaSepOne1' a (Maybe Comma)
   | CommaSepMany1' a Comma (CommaSep1' a)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
 -- | Iso to unpack a 'CommaSep'
 _CommaSep
diff --git a/src/Language/Python/Syntax/Comment.hs b/src/Language/Python/Syntax/Comment.hs
--- a/src/Language/Python/Syntax/Comment.hs
+++ b/src/Language/Python/Syntax/Comment.hs
@@ -1,4 +1,5 @@
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 {-# language TemplateHaskell #-}
 
 {-|
@@ -12,8 +13,13 @@
 
 module Language.Python.Syntax.Comment where
 
+import Control.Lens.Lens (Lens')
+import Data.Generics.Product.Typed (typed)
 import Data.Deriving (deriveEq1, deriveOrd1)
+import GHC.Generics (Generic)
 
+import Language.Python.Syntax.Ann
+
 -- | A Python single-line comment, such as on the following line:
 --
 -- @
@@ -35,10 +41,14 @@
 -- string expressions (since that's what they are).
 data Comment a
   = MkComment
-  { _commentAnn :: a
+  { _commentAnn :: Ann a
   , _commentValue :: String
   }
-  deriving (Eq, Ord, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Ord, Show, Functor, Foldable, Traversable, Generic)
+
+instance HasAnn Comment where
+  annot :: forall a. Lens' (Comment a) (Ann a)
+  annot = typed @(Ann a)
 
 deriveEq1 ''Comment
 deriveOrd1 ''Comment
diff --git a/src/Language/Python/Syntax/Expr.hs b/src/Language/Python/Syntax/Expr.hs
--- a/src/Language/Python/Syntax/Expr.hs
+++ b/src/Language/Python/Syntax/Expr.hs
@@ -1,9 +1,10 @@
 {-# language LambdaCase #-}
 {-# language DataKinds, KindSignatures #-}
-{-# language ScopedTypeVariables #-}
-{-# language MultiParamTypeClasses, FlexibleInstances #-}
 {-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
 {-# language ExistentialQuantification #-}
+{-# language InstanceSigs, TypeApplications #-}
+{-# language MultiParamTypeClasses, FlexibleInstances #-}
+{-# language ScopedTypeVariables #-}
 
 {-|
 Module      : Language.Python.Syntax.Expr
@@ -16,7 +17,7 @@
 
 module Language.Python.Syntax.Expr
   ( -- * Expressions
-    Expr(..), HasExprs(..), exprAnn, shouldGroupLeft, shouldGroupRight
+    Expr(..), HasExprs(..), shouldGroupLeft, shouldGroupRight
     -- * Parameters and arguments
   , Param(..), paramAnn, paramType_, paramType, paramName
   , Arg(..), argExpr
@@ -34,7 +35,7 @@
 import Control.Lens.Fold ((^?), (^?!))
 import Control.Lens.Getter ((^.), getting, to, view)
 import Control.Lens.Lens (Lens, Lens', lens)
-import Control.Lens.Plated (Plated(..), gplate)
+import Control.Lens.Plated (Plated(..))
 import Control.Lens.Prism (_Just, _Left, _Right)
 import Control.Lens.Setter ((.~), mapped, over)
 import Control.Lens.Traversal (Traversal, failing, traverseOf)
@@ -45,6 +46,7 @@
 import Data.Coerce (coerce)
 import Data.Digit.Integral (integralDecDigits)
 import Data.Function ((&))
+import Data.Generics.Product.Typed (typed)
 import Data.List.NonEmpty (NonEmpty)
 import Data.Maybe (isNothing)
 import Data.Monoid ((<>))
@@ -53,6 +55,7 @@
 import Unsafe.Coerce (unsafeCoerce)
 
 import Language.Python.Optics.Validated (Validated(..))
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Ident
 import Language.Python.Syntax.Numbers
@@ -89,13 +92,13 @@
 data Param (v :: [*]) a
   -- | @def foo(a):@
   = PositionalParam
-  { _paramAnn :: a
+  { _paramAnn :: Ann a
   , _paramName :: Ident v a
   , _paramType :: Maybe (Colon, Expr v a)
   }
   -- | @def foo(bar=None):@
   | KeywordParam
-  { _paramAnn :: a
+  { _paramAnn :: Ann a
   , _paramName :: Ident v a
   -- ':' spaces <expr>
   , _paramType :: Maybe (Colon, Expr v a)
@@ -105,7 +108,7 @@
   }
   -- | @def foo(*xs):@
   | StarParam
-  { _paramAnn :: a
+  { _paramAnn :: Ann a
   -- '*' spaces
   , _unsafeStarParamWhitespace :: [Whitespace]
   , _unsafeStarParamName :: Ident v a
@@ -114,23 +117,27 @@
   }
   -- | @def foo(*):@
   | UnnamedStarParam
-  { _paramAnn :: a
+  { _paramAnn :: Ann a
   -- '*' spaces
   , _unsafeUnnamedStarParamWhitespace :: [Whitespace]
   }
   -- | @def foo(**dict):@
   | DoubleStarParam
-  { _paramAnn :: a
+  { _paramAnn :: Ann a
   -- '**' spaces
   , _unsafeDoubleStarParamWhitespace :: [Whitespace]
   , _paramName :: Ident v a
   -- ':' spaces <expr>
   , _paramType :: Maybe (Colon, Expr v a)
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (Param v) where
+  annot :: forall a. Lens' (Param v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance IsString (Param '[] ()) where
-  fromString a = PositionalParam () (fromString a) Nothing
+  fromString a = PositionalParam (Ann ()) (fromString a) Nothing
 
 instance HasTrailingWhitespace (Param v a) where
   trailingWhitespace =
@@ -170,7 +177,7 @@
 
 -- | Lens on the syntrax tree annotation on a parameter
 paramAnn :: Lens' (Param v a) a
-paramAnn = lens _paramAnn (\s a -> s { _paramAnn = a})
+paramAnn = lens (getAnn . _paramAnn) (\s a -> s { _paramAnn = Ann a})
 
 -- | A faux-lens on the optional Python type annotation which may follow a parameter
 --
@@ -261,29 +268,34 @@
 -- @
 data Arg (v :: [*]) a
   = PositionalArg
-  { _argAnn :: a
+  { _argAnn :: Ann a
   , _argExpr :: Expr v a
   }
   | KeywordArg
-  { _argAnn :: a
+  { _argAnn :: Ann a
   , _unsafeKeywordArgName :: Ident v a
   , _unsafeKeywordArgWhitespaceRight :: [Whitespace]
   , _argExpr :: Expr v a
   }
   | StarArg
-  { _argAnn :: a
+  { _argAnn :: Ann a
   , _unsafeStarArgWhitespace :: [Whitespace]
   , _argExpr :: Expr v a
   }
   | DoubleStarArg
-  { _argAnn :: a
+  { _argAnn :: Ann a
   , _unsafeDoubleStarArgWhitespace :: [Whitespace]
   , _argExpr :: Expr v a
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
-instance IsString (Arg '[] ()) where; fromString = PositionalArg () . fromString
+instance HasAnn (Arg v) where
+  annot :: forall a. Lens' (Arg v a) (Ann a)
+  annot = typed @(Ann a)
 
+instance IsString (Arg '[] ()) where
+  fromString = PositionalArg (Ann ()) . fromString
+
 -- | Lens on the Python expression which is passed as the argument
 argExpr :: Lens (Arg v a) (Arg '[] a) (Expr v a) (Expr '[] a)
 argExpr = lens _argExpr (\s a -> (s ^. unvalidated) { _argExpr = a })
@@ -300,9 +312,17 @@
 -- x for y in z
 -- @
 data Comprehension e (v :: [*]) a
-  = Comprehension a (e v a) (CompFor v a) [Either (CompFor v a) (CompIf v a)] -- ^ <expr> <comp_for> (comp_for | comp_if)*
-  deriving (Eq, Show)
+  = Comprehension
+      (Ann a)
+      (e v a)
+      (CompFor v a)
+      [Either (CompFor v a) (CompIf v a)] -- ^ <expr> <comp_for> (comp_for | comp_if)*
+  deriving (Eq, Show, Generic)
 
+instance HasAnn (Comprehension e v) where
+  annot :: forall a. Lens' (Comprehension e v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasTrailingWhitespace (Comprehension e v a) where
   trailingWhitespace =
     lens
@@ -320,25 +340,29 @@
 
 instance Functor (e v) => Functor (Comprehension e v) where
   fmap f (Comprehension a b c d) =
-    Comprehension (f a) (fmap f b) (fmap f c) (fmap (bimap (fmap f) (fmap f)) d)
+    Comprehension (f <$> a) (fmap f b) (fmap f c) (fmap (bimap (fmap f) (fmap f)) d)
 
 instance Foldable (e v) => Foldable (Comprehension e v) where
   foldMap f (Comprehension a b c d) =
-    f a <> foldMap f b <> foldMap f c <> foldMap (bifoldMap (foldMap f) (foldMap f)) d
+    foldMap f a <> foldMap f b <> foldMap f c <> foldMap (bifoldMap (foldMap f) (foldMap f)) d
 
 instance Traversable (e v) => Traversable (Comprehension e v) where
   traverse f (Comprehension a b c d) =
     Comprehension <$>
-    f a <*>
+    traverse f a <*>
     traverse f b <*>
     traverse f c <*>
     traverse (bitraverse (traverse f) (traverse f)) d
 
 -- | A condition inside a comprehension, e.g. @[x for x in xs if even(x)]@
 data CompIf (v :: [*]) a
-  = CompIf a [Whitespace] (Expr v a)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  = CompIf (Ann a) [Whitespace] (Expr v a)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (CompIf v) where
+  annot :: forall a. Lens' (CompIf v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasTrailingWhitespace (CompIf v a) where
   trailingWhitespace =
     lens
@@ -347,9 +371,13 @@
 
 -- | A nested comprehesion, e.g. @[(x, y) for x in xs for y in ys]@
 data CompFor (v :: [*]) a
-  = CompFor a [Whitespace] (Expr v a) [Whitespace] (Expr v a)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  = CompFor (Ann a) [Whitespace] (Expr v a) [Whitespace] (Expr v a)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (CompFor v) where
+  annot :: forall a. Lens' (CompFor v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasTrailingWhitespace (CompFor v a) where
   trailingWhitespace =
     lens
@@ -363,17 +391,21 @@
 -- https://docs.python.org/3/reference/expressions.html#dictionary-displays
 data DictItem (v :: [*]) a
   = DictItem
-  { _dictItemAnn :: a
+  { _dictItemAnn :: Ann a
   , _unsafeDictItemKey :: Expr v a
   , _unsafeDictItemColon :: Colon
   , _unsafeDictItemValue :: Expr v a
   }
   | DictUnpack
-  { _dictItemAnn :: a
+  { _dictItemAnn :: Ann a
   , _unsafeDictItemUnpackWhitespace :: [Whitespace]
   , _unsafeDictItemUnpackValue :: Expr v a
-  } deriving (Eq, Show, Functor, Foldable, Traversable)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (DictItem v) where
+  annot :: forall a. Lens' (DictItem v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasTrailingWhitespace (DictItem v a) where
   trailingWhitespace =
     lens
@@ -408,7 +440,7 @@
       (Maybe (Expr v a))
       -- [':' [expr]]
       (Maybe (Colon, Maybe (Expr v a)))
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
 instance HasTrailingWhitespace (Subscript v a) where
   trailingWhitespace =
@@ -447,16 +479,20 @@
 -- https://docs.python.org/3/reference/expressions.html#list-displays
 data ListItem (v :: [*]) a
   = ListItem
-  { _listItemAnn :: a
+  { _listItemAnn :: Ann a
   , _unsafeListItemValue :: Expr v a
   }
   | ListUnpack
-  { _listItemAnn :: a
+  { _listItemAnn :: Ann a
   , _unsafeListUnpackParens :: [([Whitespace], [Whitespace])]
   , _unsafeListUnpackWhitespace :: [Whitespace]
   , _unsafeListUnpackValue :: Expr v a
-  } deriving (Eq, Show, Functor, Foldable, Traversable)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (ListItem v) where
+  annot :: forall a. Lens' (ListItem v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasExprs ListItem where
   _Exprs f (ListItem a b) = ListItem a <$> f b
   _Exprs f (ListUnpack a b c d) = ListUnpack a b c <$> f d
@@ -481,16 +517,20 @@
 -- https://docs.python.org/3/reference/expressions.html#set-displays
 data SetItem (v :: [*]) a
   = SetItem
-  { _setItemAnn :: a
+  { _setItemAnn :: Ann a
   , _unsafeSetItemValue :: Expr v a
   }
   | SetUnpack
-  { _setItemAnn :: a
+  { _setItemAnn :: Ann a
   , _unsafeSetUnpackParens :: [([Whitespace], [Whitespace])]
   , _unsafeSetUnpackWhitespace :: [Whitespace]
   , _unsafeSetUnpackValue :: Expr v a
-  } deriving (Eq, Show, Functor, Foldable, Traversable)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (SetItem v) where
+  annot :: forall a. Lens' (SetItem v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasExprs SetItem where
   _Exprs f (SetItem a b) = SetItem a <$> f b
   _Exprs f (SetUnpack a b c d) = SetUnpack a b c <$> f d
@@ -513,16 +553,20 @@
 -- Used to construct tuples, e.g. @(1, 'x', **c)@
 data TupleItem (v :: [*]) a
   = TupleItem
-  { _tupleItemAnn :: a
+  { _tupleItemAnn :: Ann a
   , _unsafeTupleItemValue :: Expr v a
   }
   | TupleUnpack
-  { _tupleItemAnn :: a
+  { _tupleItemAnn :: Ann a
   , _unsafeTupleUnpackParens :: [([Whitespace], [Whitespace])]
   , _unsafeTupleUnpackWhitespace :: [Whitespace]
   , _unsafeTupleUnpackValue :: Expr v a
-  } deriving (Eq, Show, Functor, Foldable, Traversable)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (TupleItem v) where
+  annot :: forall a. Lens' (TupleItem v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasExprs TupleItem where
   _Exprs f (TupleItem a b) = TupleItem a <$> f b
   _Exprs f (TupleUnpack a b c d) = TupleUnpack a b c <$> f d
@@ -546,7 +590,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#parenthesized-forms
   = Unit
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   , _unsafeUnitWhitespaceInner :: [Whitespace]
   , _unsafeUnitWhitespaceRight :: [Whitespace]
   }
@@ -554,7 +598,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#lambda
   | Lambda
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   , _unsafeLambdaWhitespace :: [Whitespace]
   , _unsafeLambdaArgs :: CommaSep (Param v a)
   , _unsafeLambdaColon :: Colon
@@ -568,7 +612,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#yield-expressions
   | Yield
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   , _unsafeYieldWhitespace :: [Whitespace]
   , _unsafeYieldValue :: CommaSep (Expr v a)
   }
@@ -576,7 +620,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#yield-expressions
   | YieldFrom
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   , _unsafeYieldWhitespace :: [Whitespace]
   , _unsafeFromWhitespace :: [Whitespace]
   , _unsafeYieldFromValue :: Expr v a
@@ -585,7 +629,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#conditional-expressions
   | Ternary
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   -- expr
   , _unsafeTernaryValue :: Expr v a
   -- 'if' spaces
@@ -601,7 +645,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#list-displays
   | ListComp
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   -- [ spaces
   , _unsafeListCompWhitespaceLeft :: [Whitespace]
   -- comprehension
@@ -613,7 +657,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#list-displays
   | List
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   -- [ spaces
   , _unsafeListWhitespaceLeft :: [Whitespace]
   -- exprs
@@ -625,7 +669,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#dictionary-displays
   | DictComp
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   -- { spaces
   , _unsafeDictCompWhitespaceLeft :: [Whitespace]
   -- comprehension
@@ -639,7 +683,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#dictionary-displays
   | Dict
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   , _unsafeDictWhitespaceLeft :: [Whitespace]
   , _unsafeDictValues :: Maybe (CommaSep1' (DictItem v a))
   , _unsafeDictWhitespaceRight :: [Whitespace]
@@ -648,7 +692,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#set-displays
   | SetComp
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   -- { spaces
   , _unsafeSetCompWhitespaceLeft :: [Whitespace]
   -- comprehension
@@ -660,7 +704,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#set-displays
   | Set
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   , _unsafeSetWhitespaceLeft :: [Whitespace]
   , _unsafeSetValues :: CommaSep1' (SetItem v a)
   , _unsafeSetWhitespaceRight :: [Whitespace]
@@ -669,7 +713,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#attribute-references
   | Deref
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   -- expr
   , _unsafeDerefValueLeft :: Expr v a
   -- . spaces
@@ -687,7 +731,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#subscriptions
   | Subscript
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   -- expr
   , _unsafeSubscriptValueLeft :: Expr v a
   -- [ spaces
@@ -701,7 +745,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#calls
   | Call
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   -- expr
   , _unsafeCallFunction :: Expr v a
   -- ( spaces
@@ -715,14 +759,14 @@
   --
   -- https://docs.python.org/3/library/constants.html#None
   | None
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   , _unsafeNoneWhitespace :: [Whitespace]
   }
   -- | @...@
   --
   -- https://docs.python.org/3/library/constants.html#Ellipsis
   | Ellipsis
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   , _unsafeEllipsisWhitespace :: [Whitespace]
   }
   -- | @a + b@
@@ -743,7 +787,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#boolean-operations
   | BinOp
-  { _unsafeExprAnn :: a
+  { _unsafeExprAnn :: Ann a
   , _unsafeBinOpExprLeft :: Expr v a
   , _unsafeBinOpOp :: BinOp a
   , _unsafeBinOpExprRight :: Expr v a
@@ -756,12 +800,12 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations
   | UnOp
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   , _unsafeUnOpOp :: UnOp a
   , _unsafeUnOpValue :: Expr v a
   }
   | Parens
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   -- ( spaces
   , _unsafeParensWhitespaceLeft :: [Whitespace]
   -- expr
@@ -773,7 +817,8 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#atom-identifiers
   | Ident
-  { _unsafeIdentValue :: Ident v a
+  { _exprAnn :: Ann a
+  , _unsafeIdentValue :: Ident v a
   }
   -- | @1@
   --
@@ -785,7 +830,7 @@
   --
   -- https://docs.python.org/3/reference/lexical_analysis.html#grammar-token-integer
   | Int
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   , _unsafeIntValue :: IntLiteral a
   , _unsafeIntWhitespace :: [Whitespace]
   }
@@ -797,7 +842,7 @@
   --
   -- https://docs.python.org/3/reference/lexical_analysis.html#floating-point-literals
   | Float
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   , _unsafeFloatValue :: FloatLiteral a
   , _unsafeFloatWhitespace :: [Whitespace]
   }
@@ -807,7 +852,7 @@
   --
   -- https://docs.python.org/3/reference/lexical_analysis.html#floating-point-literals
   | Imag
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   , _unsafeImagValue :: ImagLiteral a
   , _unsafeImagWhitespace :: [Whitespace]
   }
@@ -819,7 +864,7 @@
   --
   -- https://docs.python.org/3/library/constants.html#False
   | Bool
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   , _unsafeBoolValue :: Bool
   , _unsafeBoolWhitespace :: [Whitespace]
   }
@@ -833,7 +878,7 @@
   --
   -- https://docs.python.org/3/reference/lexical_analysis.html#grammar-token-stringliteral
   | String
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   , _unsafeStringValue :: NonEmpty (StringLiteral a)
   }
   -- | @a, b, c@
@@ -844,7 +889,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#expression-lists
   | Tuple
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   -- expr
   , _unsafeTupleHead :: TupleItem v a
   -- , spaces
@@ -856,7 +901,7 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#boolean-operations
   | Not
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   , _unsafeNotWhitespace :: [Whitespace]
   , _unsafeNotValue :: Expr v a
   }
@@ -864,84 +909,22 @@
   --
   -- https://docs.python.org/3/reference/expressions.html#generator-expressions
   | Generator
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   , _generatorValue :: Comprehension Expr v a
   }
   -- | @await a@
   --
   -- https://docs.python.org/3/reference/expressions.html#await
   | Await
-  { _unsafeExprAnn :: a
+  { _exprAnn :: Ann a
   , _unsafeAwaitWhitespace :: [Whitespace]
   , _unsafeAwaitValue :: Expr v a
   }
   deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
--- | Lens on the top-level annotation in an expression
-exprAnn :: Lens' (Expr v a) a
-exprAnn =
-  lens
-    (\case
-        Unit a _ _ -> a
-        Lambda a _ _ _ _ -> a
-        Yield a _ _ -> a
-        YieldFrom a _ _ _ -> a
-        Ternary a _ _ _ _ _ -> a
-        None a _ -> a
-        Ellipsis a _ -> a
-        List a _ _ _ -> a
-        ListComp a _ _ _ -> a
-        Deref a _ _ _ -> a
-        Subscript a _ _ _ _ -> a
-        Call a _ _ _ _ -> a
-        BinOp a _ _ _ -> a
-        UnOp a _ _ -> a
-        Parens a _ _ _ -> a
-        Ident a -> a ^. identAnn
-        Int a _ _ -> a
-        Float a _ _ -> a
-        Imag a _ _ -> a
-        Bool a _ _ -> a
-        String a _ -> a
-        Not a _ _ -> a
-        Tuple a _ _ _ -> a
-        DictComp a _ _ _ -> a
-        Dict a _ _ _ -> a
-        SetComp a _ _ _ -> a
-        Set a _ _ _ -> a
-        Generator a _ -> a
-        Await a _ _ -> a)
-    (\e ann ->
-      case e of
-        Unit _ a b -> Unit ann a b
-        Lambda _ a b c d -> Lambda ann a b c d
-        Yield _ a b -> Yield ann a b
-        YieldFrom ann a b c -> YieldFrom ann a b c
-        Ternary ann a b c d e -> Ternary ann a b c d e
-        None _ a -> None ann a
-        Ellipsis _ a -> Ellipsis ann a
-        List _ a b c -> List ann a b c
-        ListComp _ a b c -> ListComp ann a b c
-        Deref _ a b c -> Deref ann a b c
-        Subscript _ a b c d -> Subscript ann a b c d
-        Call _ a b c d -> Call ann a b c d
-        BinOp _ a b c -> BinOp ann a b c
-        UnOp _ a b -> UnOp ann a b
-        Parens _ a b c -> Parens ann a b c
-        Ident a -> Ident $ a & identAnn .~ ann
-        Int _ a b -> Int ann a b
-        Float _ a b -> Float ann a b
-        Imag _ a b -> Imag ann a b
-        Bool _ a b -> Bool ann a b
-        String _ a -> String ann a
-        Not _ a b -> Not ann a b
-        Tuple _ a b c -> Tuple ann a b c
-        DictComp _ a b c -> DictComp ann a b c
-        Dict _ a b c -> Dict ann a b c
-        SetComp _ a b c -> SetComp ann a b c
-        Set _ a b c -> Set ann a b c
-        Generator _ a -> Generator ann a
-        Await _ a b -> Not ann a b)
+instance HasAnn (Expr v) where
+  annot :: forall a. Lens' (Expr v a) (Ann a)
+  annot = typed @(Ann a)
 
 instance HasTrailingWhitespace (Expr v a) where
   trailingWhitespace =
@@ -963,7 +946,7 @@
           BinOp _ _ _ e -> e ^. trailingWhitespace
           UnOp _ _ e -> e ^. trailingWhitespace
           Parens _ _ _ ws -> ws
-          Ident a -> a ^. getting trailingWhitespace
+          Ident _ a -> a ^. getting trailingWhitespace
           Int _ _ ws -> ws
           Float _ _ ws -> ws
           Imag _ _ ws -> ws
@@ -996,7 +979,7 @@
           BinOp a b c e -> BinOp a (coerce b) c (e & trailingWhitespace .~ ws)
           UnOp a b c -> UnOp a b (c & trailingWhitespace .~ ws)
           Parens a b c _ -> Parens a b (coerce c) ws
-          Ident a -> Ident $ a & trailingWhitespace .~ ws
+          Ident a b -> Ident a $ b & trailingWhitespace .~ ws
           Int a b _ -> Int a b ws
           Float a b _ -> Float a b ws
           Imag a b _ -> Imag a b ws
@@ -1014,26 +997,174 @@
           Await a b c -> Await a b (c & trailingWhitespace .~ ws))
 
 instance IsString (Expr '[] ()) where
-  fromString s = Ident $ MkIdent () s []
+  fromString s = Ident (Ann ()) $ MkIdent (Ann ()) s []
 
 instance Num (Expr '[] ()) where
   fromInteger n
-    | n >= 0 = Int () (IntLiteralDec () $ integralDecDigits n ^?! _Right) []
+    | n >= 0 = Int (Ann ()) (IntLiteralDec (Ann ()) $ integralDecDigits n ^?! _Right) []
     | otherwise =
         UnOp
-          ()
-          (Negate () [])
-          (Int () (IntLiteralDec () $ integralDecDigits (-n) ^?! _Right) [])
+          (Ann ())
+          (Negate (Ann ()) [])
+          (Int (Ann ()) (IntLiteralDec (Ann ()) $ integralDecDigits (-n) ^?! _Right) [])
 
-  negate = UnOp () (Negate () [])
+  negate = UnOp (Ann ()) (Negate (Ann ()) [])
 
-  (+) a = BinOp () (a & trailingWhitespace .~ [Space]) (Plus () [Space])
-  (*) a = BinOp () (a & trailingWhitespace .~ [Space]) (Multiply () [Space])
-  (-) a = BinOp () (a & trailingWhitespace .~ [Space]) (Minus () [Space])
+  (+) a = BinOp (Ann ()) (a & trailingWhitespace .~ [Space]) (Plus (Ann ()) [Space])
+  (*) a = BinOp (Ann ()) (a & trailingWhitespace .~ [Space]) (Multiply (Ann ()) [Space])
+  (-) a = BinOp (Ann ()) (a & trailingWhitespace .~ [Space]) (Minus (Ann ()) [Space])
   signum = undefined
   abs = undefined
 
-instance Plated (Expr '[] a) where; plate = gplate
+instance Plated (Expr '[] a) where
+  plate fun e =
+    case e of
+      Unit{} -> pure e
+      Lambda a b c d e ->
+        (\c' -> Lambda a b c' d) <$>
+        (traverse.paramExpr) fun c <*>
+        fun e
+      Yield a b c ->
+        Yield a b <$> traverse fun c
+      YieldFrom a b c d ->
+        YieldFrom a b c <$> fun d
+      Ternary a b c d e f ->
+        (\b' d' -> Ternary a b' c d' e) <$>
+        fun b <*>
+        fun d <*>
+        fun f
+      None{} -> pure e
+      Ellipsis{} -> pure e
+      List a b c d ->
+        (\c' -> List a b c' d) <$>
+        (traverse.traverse.listItemExpr) fun c
+      ListComp a b c d ->
+        (\c' -> ListComp a b c' d) <$>
+        compExpr fun c
+      Deref a b c d ->
+        (\b' -> Deref a b' c d) <$>
+        fun b
+      Subscript a b c d e ->
+        (\b' d' -> Subscript a b' c d' e) <$>
+        fun b <*>
+        (traverse.subscriptExpr) fun d
+      Call a b c d e ->
+        (\b' d' -> Call a b' c d' e) <$>
+        fun b <*>
+        (traverse.traverse.argExpr) fun d
+      BinOp a b c d ->
+        (\b' -> BinOp a b' c) <$>
+        fun b <*>
+        fun d
+      UnOp a b c ->
+        UnOp a b <$> fun c
+      Parens a b c d ->
+        (\c' -> Parens a b c' d) <$>
+        fun c
+      Ident{} -> pure e
+      Int{} -> pure e
+      Float{} -> pure e
+      Imag{} -> pure e
+      Bool{} -> pure e
+      String{} -> pure e
+      Not a b c -> Not a b <$> fun c
+      Tuple a b c d ->
+        (\b' -> Tuple a b' c) <$>
+        tupleItemExpr fun b <*>
+        (traverse.traverse.tupleItemExpr) fun d
+      DictComp a b c d ->
+        (\c' -> DictComp a b c' d) <$>
+        dictCompExpr fun c
+      Dict a b c d ->
+        (\c' -> Dict a b c' d) <$>
+        (traverse.traverse.dictItemExpr) fun c
+      SetComp a b c d ->
+        (\c' -> SetComp a b c' d) <$>
+        setCompExpr fun c
+      Set a b c d ->
+        (\c' -> Set a b c' d) <$>
+        (traverse.setItemExpr) fun c
+      Generator a b -> Generator a <$> compExpr fun b
+      Await a b c -> Await a b <$> fun c
+    where
+      paramExpr fun' p =
+        case p of
+          PositionalParam a b c ->
+            PositionalParam a b <$>
+            (traverse._2) fun' c
+          KeywordParam a b c d e ->
+            (\c' -> KeywordParam a b c' d) <$>
+            (traverse._2) fun' c <*>
+            fun' e
+          UnnamedStarParam{} -> pure p
+          StarParam a b c d ->
+            StarParam a b c <$> (traverse._2) fun' d
+          DoubleStarParam a b c d ->
+            DoubleStarParam a b c <$> (traverse._2) fun' d
+
+      listItemExpr fun' li =
+        case li of
+          ListItem a b -> ListItem a <$> fun' b
+          ListUnpack a b c d -> ListUnpack a b c <$> fun' d
+
+      tupleItemExpr fun' ti =
+        case ti of
+          TupleItem a b -> TupleItem a <$> fun' b
+          TupleUnpack a b c d -> TupleUnpack a b c <$> fun' d
+
+      setItemExpr fun' si =
+        case si of
+          SetItem a b -> SetItem a <$> fun' b
+          SetUnpack a b c d -> SetUnpack a b c <$> fun' d
+
+      dictItemExpr fun' di =
+        case di of
+          DictItem a b c d ->
+            (\b' -> DictItem a b' c) <$>
+            fun' b <*>
+            fun' d
+          DictUnpack a b c -> DictUnpack a b <$> fun' c
+
+      compIfExpr fun' (CompIf a b c) = CompIf a b <$> fun' c
+
+      compForExpr fun' (CompFor a b c d e) =
+        (\c' -> CompFor a b c' d) <$>
+        fun' c <*>
+        fun' e
+
+      compExpr fun' (Comprehension a b c d) =
+        Comprehension a <$>
+        fun' b <*>
+        compForExpr fun' c <*>
+        traverse (bitraverse (compForExpr fun') (compIfExpr fun')) d
+
+      dictCompExpr fun' (Comprehension a b c d) =
+        Comprehension a <$>
+        dictItemExpr fun' b <*>
+        compForExpr fun' c <*>
+        traverse (bitraverse (compForExpr fun') (compIfExpr fun')) d
+
+      setCompExpr fun' (Comprehension a b c d) =
+        Comprehension a <$>
+        setItemExpr fun' b <*>
+        compForExpr fun' c <*>
+        traverse (bitraverse (compForExpr fun') (compIfExpr fun')) d
+
+      subscriptExpr fun' ss =
+        case ss of
+          SubscriptExpr a -> SubscriptExpr <$> fun' a
+          SubscriptSlice a b c d ->
+            (\a' -> SubscriptSlice a' b) <$>
+            traverse fun' a <*>
+            traverse fun' c <*>
+            (traverse._2.traverse) fun' d
+
+      argExpr fun' arg =
+        case arg of
+          PositionalArg a b -> PositionalArg a <$> fun' b
+          KeywordArg a b c d -> KeywordArg a b c <$> fun' d
+          StarArg a b c -> StarArg a b <$> fun' c
+          DoubleStarArg a b c -> DoubleStarArg a b <$> fun' c
 
 instance HasExprs Expr where
   _Exprs = id
diff --git a/src/Language/Python/Syntax/Ident.hs b/src/Language/Python/Syntax/Ident.hs
--- a/src/Language/Python/Syntax/Ident.hs
+++ b/src/Language/Python/Syntax/Ident.hs
@@ -1,6 +1,7 @@
 {-# language DataKinds, KindSignatures #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
 {-# language FlexibleInstances #-}
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 
 {-|
 Module      : Language.Python.Syntax.Ident
@@ -23,11 +24,14 @@
   )
 where
 
-import Control.Lens.Lens (Lens, lens)
+import Control.Lens.Lens (Lens, Lens', lens)
 import Data.Char (isDigit, isLetter)
+import Data.Generics.Product.Typed (typed)
 import Data.String (IsString(..))
+import GHC.Generics (Generic)
 
 import Language.Python.Optics.Validated (Validated)
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Raw
 import Language.Python.Syntax.Whitespace
 
@@ -39,11 +43,15 @@
 -- See <https://docs.python.org/3.5/reference/lexical_analysis.html#identifiers>
 data Ident (v :: [*]) a
   = MkIdent
-  { _identAnn :: a
+  { _identAnn :: Ann a
   , _identValue :: String
   , _identWhitespace :: [Whitespace]
-  } deriving (Eq, Show, Functor, Foldable, Traversable)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (Ident v) where
+  annot :: forall a. Lens' (Ident v a) (Ann a)
+  annot = typed @(Ann a)
+
 -- | Determine whether this character could start a valid identifier
 isIdentifierStart :: Char -> Bool
 isIdentifierStart = do
@@ -59,13 +67,13 @@
   pure $ a || b
 
 instance IsString (Raw Ident) where
-  fromString s = MkIdent () s []
+  fromString s = MkIdent (Ann ()) s []
 
 identValue :: Lens (Ident v a) (Ident '[] a) String String
 identValue = lens _identValue (\s a -> s { _identValue = a })
 
 identAnn :: Lens (Ident v a) (Ident v a) a a
-identAnn = lens _identAnn (\s a -> s { _identAnn = a })
+identAnn = annot_
 
 identWhitespace :: Lens (Ident v a) (Ident v a) [Whitespace] [Whitespace]
 identWhitespace = lens _identWhitespace (\s ws -> s { _identWhitespace = ws })
diff --git a/src/Language/Python/Syntax/Import.hs b/src/Language/Python/Syntax/Import.hs
--- a/src/Language/Python/Syntax/Import.hs
+++ b/src/Language/Python/Syntax/Import.hs
@@ -1,5 +1,6 @@
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
 {-# language DataKinds #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 {-# language LambdaCase #-}
 
 {-|
@@ -25,15 +26,19 @@
   )
 where
 
-import Control.Lens.Getter ((^.), getting)
+import Control.Lens.Getter ((^.), getting, to)
 import Control.Lens.Lens (Lens, Lens', lens)
 import Control.Lens.Prism (_Just)
 import Control.Lens.Setter ((.~))
 import Control.Lens.Tuple (_2)
 import Data.Function ((&))
 import Data.List.NonEmpty (NonEmpty)
+import Data.Generics.Product.Typed (typed)
+import GHC.Generics (Generic)
+import Unsafe.Coerce (unsafeCoerce)
 
 import Language.Python.Optics.Validated
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Ident
 import Language.Python.Syntax.Whitespace
@@ -49,29 +54,35 @@
 -- @from a import (b as c, d as e)@
 data ImportAs e v a
   = ImportAs
-  { _importAsAnn :: a
-  , _importAsName :: e a
+  { _importAsAnn :: Ann a
+  , _importAsName :: e v a
   , _importAsQual :: Maybe (NonEmpty Whitespace, Ident v a)
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
-instance Validated (ImportAs e)
+instance HasAnn (ImportAs e v) where
+  annot :: forall a. Lens' (ImportAs e v a) (Ann a)
+  annot = typed @(Ann a)
 
+instance Validated e => Validated (ImportAs e) where
+  unvalidated = to unsafeCoerce
+
 importAsAnn :: Lens' (ImportAs e v a) a
-importAsAnn = lens _importAsAnn (\s a -> s { _importAsAnn = a })
+importAsAnn = annot_
 
-importAsName :: Lens (ImportAs e v a) (ImportAs e' '[] a) (e a) (e' a)
+importAsName :: Validated e => Lens (ImportAs e v a) (ImportAs e' '[] a) (e v a) (e' '[] a)
 importAsName = lens _importAsName (\s a -> (s ^. unvalidated) { _importAsName = a })
 
 importAsQual
-  :: Lens
+  :: Validated e
+  => Lens
        (ImportAs e v a)
        (ImportAs e '[] a)
        (Maybe (NonEmpty Whitespace, Ident v a))
        (Maybe (NonEmpty Whitespace, Ident '[] a))
 importAsQual = lens _importAsQual (\s a -> (s ^. unvalidated) { _importAsQual = a })
 
-instance HasTrailingWhitespace (e a) => HasTrailingWhitespace (ImportAs e v a) where
+instance HasTrailingWhitespace (e v a) => HasTrailingWhitespace (ImportAs e v a) where
   trailingWhitespace =
     lens
       (\(ImportAs _ a b) ->
@@ -85,19 +96,23 @@
 -- | The targets of a @from ... import ...@ statement
 data ImportTargets v a
   -- | @from x import *@
-  = ImportAll a [Whitespace]
+  = ImportAll (Ann a) [Whitespace]
   -- | @from x import a, b, c@
-  | ImportSome a (CommaSep1 (ImportAs (Ident v) v a))
+  | ImportSome (Ann a) (CommaSep1 (ImportAs Ident v a))
   -- | @from x import (a, b, c)@
   | ImportSomeParens
-      a
+      (Ann a)
       -- ( spaces
       [Whitespace]
       -- imports as
-      (CommaSep1' (ImportAs (Ident v) v a))
+      (CommaSep1' (ImportAs Ident v a))
       -- ) spaces
       [Whitespace]
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
+
+instance HasAnn (ImportTargets v) where
+  annot :: forall a. Lens' (ImportTargets v a) (Ann a)
+  annot = typed @(Ann a)
 
 instance HasTrailingWhitespace (ImportTargets v a) where
   trailingWhitespace =
diff --git a/src/Language/Python/Syntax/Module.hs b/src/Language/Python/Syntax/Module.hs
--- a/src/Language/Python/Syntax/Module.hs
+++ b/src/Language/Python/Syntax/Module.hs
@@ -1,4 +1,4 @@
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
 
 {-|
 Module      : Language.Python.Syntax.Module
@@ -14,6 +14,9 @@
   )
 where
 
+import GHC.Generics (Generic)
+
+import Language.Python.Syntax.Expr
 import Language.Python.Syntax.Statement
 import Language.Python.Syntax.Whitespace
 
@@ -24,7 +27,7 @@
   | ModuleBlankFinal (Blank a)
   | ModuleBlank (Blank a) Newline (Module v a)
   | ModuleStatement (Statement v a) (Module v a)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
 instance HasStatements Module where
   _Statements f = go
@@ -33,3 +36,6 @@
       go (ModuleBlankFinal a) = pure $ ModuleBlankFinal a
       go (ModuleBlank a b c) = ModuleBlank a b <$> go c
       go (ModuleStatement a b) = ModuleStatement <$> f a <*> go b
+
+instance HasExprs Module where
+  _Exprs = _Statements._Exprs
diff --git a/src/Language/Python/Syntax/ModuleNames.hs b/src/Language/Python/Syntax/ModuleNames.hs
--- a/src/Language/Python/Syntax/ModuleNames.hs
+++ b/src/Language/Python/Syntax/ModuleNames.hs
@@ -1,5 +1,6 @@
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
 {-# language DataKinds, FlexibleInstances, MultiParamTypeClasses #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 {-# language LambdaCase #-}
 
 {-|
@@ -16,23 +17,26 @@
 -}
 
 module Language.Python.Syntax.ModuleNames
-  ( ModuleName (..)
-  , RelativeModuleName (..)
+  ( ModuleName(..)
+  , RelativeModuleName(..)
   , makeModuleName
-  , _moduleNameAnn
   )
 where
 
 import Control.Lens.Cons (_last)
 import Control.Lens.Fold ((^?!))
 import Control.Lens.Getter ((^.))
-import Control.Lens.Lens (lens)
+import Control.Lens.Lens (Lens', lens)
 import Control.Lens.Setter ((.~))
 import Data.Coerce (coerce)
 import Data.Function ((&))
+import Data.Generics.Product.Typed (typed)
 import Data.List.NonEmpty (NonEmpty(..))
+import GHC.Generics (Generic)
+
 import qualified Data.List.NonEmpty as NonEmpty
 
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Ident
 import Language.Python.Syntax.Punctuation
 import Language.Python.Syntax.Whitespace
@@ -45,20 +49,24 @@
 --
 --See <https://docs.python.org/3.5/tutorial/modules.html#intra-package-references>
 data RelativeModuleName v a
-  = RelativeWithName [Dot] (ModuleName v a)
-  | Relative (NonEmpty Dot)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  = RelativeWithName (Ann a) [Dot] (ModuleName v a)
+  | Relative (Ann a) (NonEmpty Dot)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (RelativeModuleName v) where
+  annot :: forall a. Lens' (RelativeModuleName v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasTrailingWhitespace (RelativeModuleName v a) where
   trailingWhitespace =
     lens
       (\case
-          RelativeWithName _ mn -> mn ^. trailingWhitespace
-          Relative (a :| as) -> (a : as) ^?! _last.trailingWhitespace)
+          RelativeWithName _ _ mn -> mn ^. trailingWhitespace
+          Relative _ (a :| as) -> (a : as) ^?! _last.trailingWhitespace)
       (\a ws -> case a of
-          RelativeWithName x mn -> RelativeWithName x (mn & trailingWhitespace .~ ws)
-          Relative (a :| as) ->
-            Relative .
+          RelativeWithName ann x mn -> RelativeWithName ann x (mn & trailingWhitespace .~ ws)
+          Relative ann (a :| as) ->
+            Relative ann .
             NonEmpty.fromList $
             (a : as) & _last.trailingWhitespace .~ ws)
 
@@ -69,14 +77,13 @@
 --
 -- @a.b@
 data ModuleName v a
-  = ModuleNameOne a (Ident v a)
-  | ModuleNameMany a (Ident v a) Dot (ModuleName v a)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  = ModuleNameOne (Ann a) (Ident v a)
+  | ModuleNameMany (Ann a) (Ident v a) Dot (ModuleName v a)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
--- | Get the annotation from a 'ModuleName'
-_moduleNameAnn :: ModuleName v a -> a
-_moduleNameAnn (ModuleNameOne a _) = a
-_moduleNameAnn (ModuleNameMany a _ _ _) = a
+instance HasAnn (ModuleName v) where
+  annot :: forall a. Lens' (ModuleName v a) (Ann a)
+  annot = typed @(Ann a)
 
 -- | Convenience constructor for 'ModuleName'
 makeModuleName :: Ident v a -> [([Whitespace], Ident v a)] -> ModuleName v a
diff --git a/src/Language/Python/Syntax/Numbers.hs b/src/Language/Python/Syntax/Numbers.hs
--- a/src/Language/Python/Syntax/Numbers.hs
+++ b/src/Language/Python/Syntax/Numbers.hs
@@ -1,4 +1,5 @@
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 {-# language LambdaCase #-}
 {-# language TemplateHaskell #-}
 
@@ -30,6 +31,7 @@
   )
 where
 
+import Control.Lens.Lens (Lens')
 import Control.Lens.Review ((#))
 import Data.Deriving (deriveEq1, deriveOrd1)
 import Data.Digit.Binary (BinDigit)
@@ -37,14 +39,18 @@
 import Data.Digit.Octal (OctDigit)
 import Data.Digit.Decimal (DecDigit)
 import Data.Digit.Hexadecimal.MixedCase (HeXDigit)
+import Data.Generics.Product.Typed (typed)
 import Data.List.NonEmpty (NonEmpty)
 import Data.Semigroup ((<>))
 import Data.Text (Text)
 import Data.These (These(..))
+import GHC.Generics (Generic)
 
 import qualified Data.List.NonEmpty as NonEmpty
 import qualified Data.Text as Text
 
+import Language.Python.Syntax.Ann
+
 -- | An integer literal value.
 --
 -- @5@ is an integer literal.
@@ -59,14 +65,14 @@
   --
   -- @1234@
   = IntLiteralDec
-  { _intLiteralAnn :: a
+  { _intLiteralAnn :: Ann a
   , _unsafeIntLiteralDecValue :: NonEmpty DecDigit
   }
   -- | Binary
   --
   -- @0b10110@
   | IntLiteralBin
-  { _intLiteralAnn :: a
+  { _intLiteralAnn :: Ann a
   , _unsafeIntLiteralBinUppercase :: Bool
   , _unsafeIntLiteralBinValue :: NonEmpty BinDigit
   }
@@ -74,7 +80,7 @@
   --
   -- @0o1367@
   | IntLiteralOct
-  { _intLiteralAnn :: a
+  { _intLiteralAnn :: Ann a
   , _unsafeIntLiteralOctUppercase :: Bool
   , _unsafeIntLiteralOctValue :: NonEmpty OctDigit
   }
@@ -82,26 +88,30 @@
   --
   -- @0x18B4f@
   | IntLiteralHex
-  { _intLiteralAnn :: a
+  { _intLiteralAnn :: Ann a
   , _unsafeIntLiteralHexUppercase :: Bool
   , _unsafeIntLiteralHexValue :: NonEmpty HeXDigit
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 deriveEq1 ''IntLiteral
 deriveOrd1 ''IntLiteral
 
+instance HasAnn IntLiteral where
+  annot :: forall a. Lens' (IntLiteral a) (Ann a)
+  annot = typed @(Ann a)
+
 -- | Positive or negative, as in @-7@
-data Sign = Pos | Neg deriving (Eq, Ord, Show)
+data Sign = Pos | Neg deriving (Eq, Ord, Show, Generic)
 
 -- | When a floating point literal is in scientific notation, it includes the character
 -- @e@, which can be lower or upper case.
-data E = Ee | EE deriving (Eq, Ord, Show)
+data E = Ee | EE deriving (Eq, Ord, Show, Generic)
 
 -- | The exponent of a floating point literal.
 --
 -- An @e@, followed by an optional 'Sign', followed by at least one digit.
 data FloatExponent = FloatExponent E (Maybe Sign) (NonEmpty DecDigit)
-  deriving (Eq, Ord, Show)
+  deriving (Eq, Ord, Show, Generic)
 
 -- | A literal floating point value.
 --
@@ -119,7 +129,7 @@
   --
   -- @12.34e56@
   = FloatLiteralFull
-  { _floatLiteralAnn :: a
+  { _floatLiteralAnn :: Ann a
   , _floatLiteralFullLeft :: NonEmpty DecDigit
   , _floatLiteralFullRight
       :: Maybe (These (NonEmpty DecDigit) FloatExponent)
@@ -130,7 +140,7 @@
   --
   -- @.12e34@
   | FloatLiteralPoint
-  { _floatLiteralAnn :: a
+  { _floatLiteralAnn :: Ann a
   -- . [0-9]+
   , _floatLiteralPointRight :: NonEmpty DecDigit
   -- [ 'e' ['-' | '+'] [0-9]+ ]
@@ -140,16 +150,20 @@
   --
   -- @12e34@
   | FloatLiteralWhole
-  { _floatLiteralAnn :: a
+  { _floatLiteralAnn :: Ann a
   -- [0-9]+
   , _floatLiteralWholeRight :: NonEmpty DecDigit
   -- [ 'e' ['-' | '+'] [0-9]+ ]
   , _floatLiteralWholeExponent :: FloatExponent
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 deriveEq1 ''FloatLiteral
 deriveOrd1 ''FloatLiteral
 
+instance HasAnn FloatLiteral where
+  annot :: forall a. Lens' (FloatLiteral a) (Ann a)
+  annot = typed @(Ann a)
+
 -- | Imaginary number literals
 --
 -- See <https://docs.python.org/3.5/reference/lexical_analysis.html#imaginary-literals>
@@ -158,7 +172,7 @@
   --
   -- @12j@
   = ImagLiteralInt
-  { _imagLiteralAnn :: a
+  { _imagLiteralAnn :: Ann a
   , _unsafeImagLiteralIntValue :: NonEmpty DecDigit
   , _imagLiteralUppercase :: Bool
   }
@@ -170,13 +184,17 @@
   --
   -- @.3j@
   | ImagLiteralFloat
-  { _imagLiteralAnn :: a
+  { _imagLiteralAnn :: Ann a
   , _unsafeImagLiteralFloatValue :: FloatLiteral a
   , _imagLiteralUppercase :: Bool
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 deriveEq1 ''ImagLiteral
 deriveOrd1 ''ImagLiteral
+
+instance HasAnn ImagLiteral where
+  annot :: forall a. Lens' (ImagLiteral a) (Ann a)
+  annot = typed @(Ann a)
 
 showIntLiteral :: IntLiteral a -> Text
 showIntLiteral (IntLiteralDec _ n) =
diff --git a/src/Language/Python/Syntax/Operator/Binary.hs b/src/Language/Python/Syntax/Operator/Binary.hs
--- a/src/Language/Python/Syntax/Operator/Binary.hs
+++ b/src/Language/Python/Syntax/Operator/Binary.hs
@@ -1,6 +1,7 @@
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 {-# language LambdaCase #-}
 {-# language MultiParamTypeClasses, FlexibleInstances #-}
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
 {-# language TemplateHaskell #-}
 
 {-|
@@ -19,69 +20,74 @@
 module Language.Python.Syntax.Operator.Binary where
 
 import Control.Lens.Getter ((^.))
-import Control.Lens.Lens (lens)
+import Control.Lens.Lens (Lens', lens)
 import Control.Lens.TH (makeLenses)
 import Data.Functor (($>))
+import Data.Generics.Product.Typed (typed)
 import Data.Semigroup ((<>))
+import GHC.Generics (Generic)
 
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Whitespace
 
 -- | A Python binary operator, such as @+@, along with its trailing 'Whitespace'
---
--- The type variable allows annotations, but it can simply be made @()@ for an unannotated @BinOp@.
 data BinOp a
   -- | @a is b@
-  = Is a [Whitespace]
+  = Is (Ann a) [Whitespace]
   -- | @a is not b@
-  | IsNot a [Whitespace] [Whitespace]
+  | IsNot (Ann a) [Whitespace] [Whitespace]
   -- | @a in b@
-  | In a [Whitespace]
+  | In (Ann a) [Whitespace]
   -- | @a not in b@
-  | NotIn a [Whitespace] [Whitespace]
+  | NotIn (Ann a) [Whitespace] [Whitespace]
   -- | @a - b@
-  | Minus a [Whitespace]
+  | Minus (Ann a) [Whitespace]
   -- | @a ** b@
-  | Exp a [Whitespace]
+  | Exp (Ann a) [Whitespace]
   -- | @a and b@
-  | BoolAnd a [Whitespace]
+  | BoolAnd (Ann a) [Whitespace]
   -- | @a or b@
-  | BoolOr a [Whitespace]
+  | BoolOr (Ann a) [Whitespace]
   -- | @a == b@
-  | Eq a [Whitespace]
+  | Eq (Ann a) [Whitespace]
   -- | @a < b@
-  | Lt a [Whitespace]
+  | Lt (Ann a) [Whitespace]
   -- | @a <= b@
-  | LtEq a [Whitespace]
+  | LtEq (Ann a) [Whitespace]
   -- | @a > b@
-  | Gt a [Whitespace]
+  | Gt (Ann a) [Whitespace]
   -- | @a >= b@
-  | GtEq a [Whitespace]
+  | GtEq (Ann a) [Whitespace]
   -- | @a != b@
-  | NotEq a [Whitespace]
+  | NotEq (Ann a) [Whitespace]
   -- | @a * b@
-  | Multiply a [Whitespace]
+  | Multiply (Ann a) [Whitespace]
   -- | @a / b@
-  | Divide a [Whitespace]
+  | Divide (Ann a) [Whitespace]
   -- | @a // b@
-  | FloorDivide a [Whitespace]
+  | FloorDivide (Ann a) [Whitespace]
   -- | @a % b@
-  | Percent a [Whitespace]
+  | Percent (Ann a) [Whitespace]
   -- | @a + b@
-  | Plus a [Whitespace]
+  | Plus (Ann a) [Whitespace]
   -- | @a | b@
-  | BitOr a [Whitespace]
+  | BitOr (Ann a) [Whitespace]
   -- | @a ^ b@
-  | BitXor a [Whitespace]
+  | BitXor (Ann a) [Whitespace]
   -- | @a & b@
-  | BitAnd a [Whitespace]
+  | BitAnd (Ann a) [Whitespace]
   -- | @a << b@
-  | ShiftLeft a [Whitespace]
+  | ShiftLeft (Ann a) [Whitespace]
   -- | @a >> b@
-  | ShiftRight a [Whitespace]
+  | ShiftRight (Ann a) [Whitespace]
   -- | @a @ b@
-  | At a [Whitespace]
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  | At (Ann a) [Whitespace]
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn BinOp where
+  annot :: forall a. Lens' (BinOp a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasTrailingWhitespace (BinOp a) where
   trailingWhitespace =
     lens
@@ -193,8 +199,8 @@
   , entry Exp 30 R
   ]
   where
-    entry a = OpEntry (a () [])
-    entry1 a = OpEntry (a () [] [])
+    entry a = OpEntry (a (Ann ()) [])
+    entry1 a = OpEntry (a (Ann ()) [] [])
 
 -- | Compare two 'BinOp's to determine whether they represent the same operator, ignoring annotations and trailing whitespace.
 sameOperator :: BinOp a -> BinOp a' -> Bool
diff --git a/src/Language/Python/Syntax/Operator/Unary.hs b/src/Language/Python/Syntax/Operator/Unary.hs
--- a/src/Language/Python/Syntax/Operator/Unary.hs
+++ b/src/Language/Python/Syntax/Operator/Unary.hs
@@ -1,4 +1,5 @@
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 {-# language LambdaCase #-}
 
 {-|
@@ -14,19 +15,27 @@
 
 module Language.Python.Syntax.Operator.Unary where
 
-import Control.Lens.Lens (lens)
+import Control.Lens.Lens (Lens', lens)
+import Data.Generics.Product.Typed (typed)
+import GHC.Generics (Generic)
+
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Whitespace
 
 -- | An 'UnOp' is a unary operator in Python, such as @-@ for negation.
 -- An operator is stored with an annotation and its trailing whitespace.
 data UnOp a
   -- | @-a@
-  = Negate a [Whitespace]
+  = Negate (Ann a) [Whitespace]
   -- | @+a@
-  | Positive a [Whitespace]
+  | Positive (Ann a) [Whitespace]
   -- | @~a@
-  | Complement a [Whitespace]
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  | Complement (Ann a) [Whitespace]
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
+
+instance HasAnn UnOp where
+  annot :: forall a. Lens' (UnOp a) (Ann a)
+  annot = typed @(Ann a)
 
 instance HasTrailingWhitespace (UnOp a) where
   trailingWhitespace =
diff --git a/src/Language/Python/Syntax/Punctuation.hs b/src/Language/Python/Syntax/Punctuation.hs
--- a/src/Language/Python/Syntax/Punctuation.hs
+++ b/src/Language/Python/Syntax/Punctuation.hs
@@ -1,4 +1,6 @@
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
+
 {-|
 Module      : Language.Python.Syntax.Punctuation
 Copyright   : (C) CSIRO 2017-2019
@@ -12,12 +14,15 @@
 
 module Language.Python.Syntax.Punctuation where
 
-import Control.Lens.Lens (lens)
+import Control.Lens.Lens (Lens', lens)
+import Data.Generics.Product.Typed (typed)
+import GHC.Generics (Generic)
 
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Whitespace
 
 -- | A period character, possibly followed by some whitespace.
-data Dot = MkDot [Whitespace]
+newtype Dot = MkDot [Whitespace]
   deriving (Eq, Show)
 
 instance HasTrailingWhitespace Dot where
@@ -26,21 +31,25 @@
 
 -- | The venerable comma separator
 newtype Comma = MkComma [Whitespace]
-  deriving (Eq, Show)
+  deriving (Eq, Show, Generic)
 
 instance HasTrailingWhitespace Comma where
   trailingWhitespace =
     lens (\(MkComma ws) -> ws) (\_ ws -> MkComma ws)
 
 newtype Colon = MkColon [Whitespace]
-  deriving (Eq, Show)
+  deriving (Eq, Show, Generic)
 
 instance HasTrailingWhitespace Colon where
   trailingWhitespace =
     lens (\(MkColon ws) -> ws) (\_ ws -> MkColon ws)
 
-data Semicolon a = MkSemicolon a [Whitespace]
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+data Semicolon a = MkSemicolon (Ann a) [Whitespace]
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
+
+instance HasAnn Semicolon where
+  annot :: forall a. Lens' (Semicolon a) (Ann a)
+  annot = typed @(Ann a)
 
 instance HasTrailingWhitespace (Semicolon a) where
   trailingWhitespace =
diff --git a/src/Language/Python/Syntax/Statement.hs b/src/Language/Python/Syntax/Statement.hs
--- a/src/Language/Python/Syntax/Statement.hs
+++ b/src/Language/Python/Syntax/Statement.hs
@@ -2,6 +2,7 @@
 {-# language DataKinds, KindSignatures #-}
 {-# language MultiParamTypeClasses, FlexibleInstances #-}
 {-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 {-# language TypeFamilies #-}
 {-# language LambdaCase #-}
 {-# language UndecidableInstances #-}
@@ -56,6 +57,7 @@
 import Control.Lens.Cons (_last)
 import Control.Lens.Fold (foldMapOf, folded)
 import Control.Lens.Getter ((^.), to, view)
+import Control.Lens.Lens (Lens')
 import Control.Lens.Plated (Plated(..), gplate)
 import Control.Lens.Prism (_Right)
 import Control.Lens.Setter ((.~), over, mapped)
@@ -66,6 +68,7 @@
 import Data.Bifunctor (bimap)
 import Data.Bitraversable (bitraverse)
 import Data.Coerce (coerce)
+import Data.Generics.Product.Typed (typed)
 import Data.List.NonEmpty (NonEmpty)
 import Data.Maybe (isNothing)
 import Data.Monoid ((<>))
@@ -75,6 +78,7 @@
 import qualified Data.List.NonEmpty as NonEmpty
 
 import Language.Python.Optics.Validated
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.AugAssign
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Comment
@@ -107,7 +111,7 @@
   { _blockBlankLines :: [(Blank a, Newline)] -- ^ Blank lines at the beginning of the block
   , _blockHead :: Statement v a -- ^ The first statement of the block
   , _blockTail :: [Either (Blank a, Newline) (Statement v a)] -- ^ The remaining items of the block, which may be statements or blank lines
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Generic)
 
 instance Functor (Block v) where
   fmap f (Block a b c) =
@@ -195,7 +199,7 @@
       (Maybe (Semicolon a))
       (Maybe (Comment a))
       (Maybe Newline)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
 -- | A 'Statement' is either a 'SmallStatement' or a 'CompoundStatement'
 --
@@ -203,8 +207,11 @@
 data Statement (v :: [*]) a
   = SmallStatement (Indents a) (SmallStatement v a)
   | CompoundStatement (CompoundStatement v a)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasStatements Statement where
+  _Statements = id
+
 instance HasExprs SmallStatement where
   _Exprs f (MkSmallStatement s ss a b c) =
     MkSmallStatement <$>
@@ -267,55 +274,55 @@
   -- | @\'return\' \<spaces\> [\<expr\>]@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-return-statement
-  = Return a [Whitespace] (Maybe (Expr v a))
+  = Return (Ann a) [Whitespace] (Maybe (Expr v a))
   -- | @\<expr\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#expression-statements
-  | Expr a (Expr v a)
+  | Expr (Ann a) (Expr v a)
   -- | @\<expr\> (\'=\' \<spaces\> \<expr\>)+@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#assignment-statements
-  | Assign a (Expr v a) (NonEmpty (Equals, Expr v a))
+  | Assign (Ann a) (Expr v a) (NonEmpty (Equals, Expr v a))
   -- | @\<expr\> \<augassign\> \<expr\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#augmented-assignment-statements
-  | AugAssign a (Expr v a) (AugAssign a) (Expr v a)
+  | AugAssign (Ann a) (Expr v a) (AugAssign a) (Expr v a)
   -- | @\'pass\' \<spaces\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-pass-statement
-  | Pass a [Whitespace]
+  | Pass (Ann a) [Whitespace]
   -- | @\'break\' \<spaces\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-break-statement
-  | Break a [Whitespace]
+  | Break (Ann a) [Whitespace]
   -- | @\'continue\' \<spaces\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-continue-statement
-  | Continue a [Whitespace]
+  | Continue (Ann a) [Whitespace]
   -- | @\'global\' \<spaces\> \<idents\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-global-statement
-  | Global a (NonEmpty Whitespace) (CommaSep1 (Ident v a))
+  | Global (Ann a) (NonEmpty Whitespace) (CommaSep1 (Ident v a))
   -- | @\'nonlocal\' \<spaces\> \<idents\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-nonlocal-statement
-  | Nonlocal a (NonEmpty Whitespace) (CommaSep1 (Ident v a))
+  | Nonlocal (Ann a) (NonEmpty Whitespace) (CommaSep1 (Ident v a))
   -- | @\'del\' \<spaces\> \<exprs\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-del-statement
-  | Del a [Whitespace] (CommaSep1' (Expr v a))
+  | Del (Ann a) [Whitespace] (CommaSep1' (Expr v a))
   -- | @\'import\' \<spaces\> \<modulenames\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-import-statement
   | Import
-      a
+      (Ann a)
       (NonEmpty Whitespace)
-      (CommaSep1 (ImportAs (ModuleName v) v a))
+      (CommaSep1 (ImportAs ModuleName v a))
   -- | @\'from\' \<spaces\> \<relative_module_name\> \'import\' \<spaces\> \<import_targets\>@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-import-statement
   | From
-      a
+      (Ann a)
       [Whitespace]
       (RelativeModuleName v a)
       [Whitespace]
@@ -323,18 +330,22 @@
   -- | @\'raise\' \<spaces\> [\<expr\> [\'as\' \<spaces\> \<expr\>]]@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-raise-statement
-  | Raise a
+  | Raise (Ann a)
       [Whitespace]
       (Maybe (Expr v a, Maybe ([Whitespace], Expr v a)))
   -- | @\'assert\' \<spaces\> \<expr\> [\',\' \<spaces\> \<expr\>]@
   --
   -- https://docs.python.org/3.5/reference/simple_stmts.html#the-assert-statement
-  | Assert a
+  | Assert (Ann a)
       [Whitespace]
       (Expr v a)
       (Maybe (Comma, Expr v a))
   deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (SimpleStatement v) where
+  annot :: forall a. Lens' (SimpleStatement v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance Plated (SimpleStatement '[] a) where; plate = gplate
 
 instance HasExprs SimpleStatement where
@@ -360,33 +371,45 @@
 -- | See <https://docs.python.org/3.5/reference/compound_stmts.html#the-try-statement>
 data ExceptAs (v :: [*]) a
   = ExceptAs
-  { _exceptAsAnn :: a
+  { _exceptAsAnn :: Ann a
   , _exceptAsExpr :: Expr v a -- ^ @\<expr\>@
   , _exceptAsName :: Maybe ([Whitespace], Ident v a) -- ^ @[\'as\' \<ident\>]@
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (ExceptAs v) where
+  annot :: forall a. Lens' (ExceptAs v a) (Ann a)
+  annot = typed @(Ann a)
+
 -- | A compound statement consists of one or more clauses.
 -- A clause consists of a header and a suite.
 data Suite (v :: [*]) a
   -- ':' <space> smallStatement
-  = SuiteOne a Colon (SmallStatement v a)
-  | SuiteMany a
+  = SuiteOne (Ann a) Colon (SmallStatement v a)
+  | SuiteMany (Ann a)
       -- ':' <spaces> [comment] <newline>
       Colon (Maybe (Comment a)) Newline
       -- <block>
       (Block v a)
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (Suite v) where
+  annot :: forall a. Lens' (Suite v a) (Ann a)
+  annot = typed @(Ann a)
+
 -- | See <https://docs.python.org/3.5/reference/compound_stmts.html#the-with-statement>
 data WithItem (v :: [*]) a
   = WithItem
-  { _withItemAnn :: a
+  { _withItemAnn :: Ann a
   , _withItemValue :: Expr v a -- ^ @\<expr\>@
   , _withItemBinder :: Maybe ([Whitespace], Expr v a) -- ^ @[\'as\' \<spaces\> \<expr\>]@
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (WithItem v) where
+  annot :: forall a. Lens' (WithItem v a) (Ann a)
+  annot = typed @(Ann a)
+
 -- | Decorators on function definitions
 --
 -- <https://docs.python.org/3.5/reference/compound_stmts.html#function-definitions>
@@ -394,7 +417,7 @@
 -- <https://docs.python.org/3.5/glossary.html#term-decorator>
 data Decorator (v :: [*]) a
   = Decorator
-  { _decoratorAnn :: a
+  { _decoratorAnn :: Ann a
   , _decoratorIndents :: Indents a -- ^ Preceding indentation
   , _decoratorAt :: At -- ^ @\'\@\' \<spaces\>@
   , _decoratorExpr :: Expr v a -- ^ @\<expr\>@
@@ -402,15 +425,19 @@
   , _decoratorNewline :: Newline -- ^ Trailing newline
   , _decoratorBlankLines :: [(Blank a, Newline)] -- ^ Trailing blank lines
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (Decorator v) where
+  annot :: forall a. Lens' (Decorator v a) (Ann a)
+  annot = typed @(Ann a)
+
 -- | See <https://docs.python.org/3.5/reference/compound_stmts.html>
 data CompoundStatement (v :: [*]) a
   -- | https://docs.python.org/3.5/reference/compound_stmts.html#function-definitions
   --
   -- https://docs.python.org/3.5/reference/compound_stmts.html#coroutine-function-definition
   = Fundef
-  { _csAnn :: a
+  { _csAnn :: Ann a
   , _unsafeCsFundefDecorators :: [Decorator v a] -- ^ Preceding 'Decorator's
   , _csIndents :: Indents a -- ^ Preceding indentation
   , _unsafeCsFundefAsync :: Maybe (NonEmpty Whitespace) -- ^ @[\'async\' \<spaces\>]@
@@ -424,7 +451,7 @@
   }
   -- | https://docs.python.org/3.5/reference/compound_stmts.html#the-if-statement
   | If
-  { _csAnn :: a
+  { _csAnn :: Ann a
   , _csIndents :: Indents a -- ^ Preceding indentation
   , _unsafeCsIfIf :: [Whitespace] -- ^ @\'if\' \<spaces\>@
   , _unsafeCsIfCond :: Expr v a -- ^ @\<expr\>@
@@ -434,7 +461,7 @@
   }
   -- | https://docs.python.org/3.5/reference/compound_stmts.html#the-while-statement
   | While
-  { _csAnn :: a
+  { _csAnn :: Ann a
   , _csIndents :: Indents a -- ^ Preceding indentation
   , _unsafeCsWhileWhile :: [Whitespace] -- ^ @\'while\' \<spaces\>@
   , _unsafeCsWhileCond :: Expr v a -- ^ @\<expr\>@
@@ -444,7 +471,7 @@
   }
   -- | https://docs.python.org/3.5/reference/compound_stmts.html#the-try-statement
   | TryExcept
-  { _csAnn :: a
+  { _csAnn :: Ann a
   , _csIndents :: Indents a -- ^ Preceding indentation
   , _unsafeCsTryExceptTry :: [Whitespace] -- ^ @\'try\' \<spaces\>@
   , _unsafeCsTryExceptBody :: Suite v a -- ^ @\<suite\>@
@@ -454,7 +481,7 @@
   }
   -- | https://docs.python.org/3.5/reference/compound_stmts.html#the-try-statement
   | TryFinally
-  { _csAnn :: a
+  { _csAnn :: Ann a
   , _csIndents :: Indents a -- ^ Preceding indentation
   , _unsafeCsTryFinallyTry :: [Whitespace] -- ^ @\'try\' \<spaces\>@
   , _unsafeCsTryFinallyTryBody :: Suite v a -- ^ @\<suite\>@
@@ -466,7 +493,7 @@
   --
   -- https://docs.python.org/3.5/reference/compound_stmts.html#the-async-for-statement
   | For
-  { _csAnn :: a
+  { _csAnn :: Ann a
   , _csIndents :: Indents a -- ^ Preceding indentation
   , _unsafeCsForAsync :: Maybe (NonEmpty Whitespace) -- ^ @[\'async\' \<spaces\>]@
   , _unsafeCsForFor :: [Whitespace] -- ^ @\'for\' \<spaces\>@
@@ -478,7 +505,7 @@
   }
   -- | https://docs.python.org/3.5/reference/compound_stmts.html#class-definitions
   | ClassDef
-  { _csAnn :: a
+  { _csAnn :: Ann a
   , _unsafeCsClassDefDecorators :: [Decorator v a] -- ^ Preceding 'Decorator's
   , _csIndents :: Indents a -- ^ Preceding indentation
   , _unsafeCsClassDefClass :: NonEmpty Whitespace -- ^ @\'class\' \<spaces\>@
@@ -490,15 +517,19 @@
   --
   -- https://docs.python.org/3.5/reference/compound_stmts.html#the-async-with-statement
   | With
-  { _csAnn :: a
+  { _csAnn :: Ann a
   , _csIndents :: Indents a -- ^ Preceding indentation
   , _unsafeCsWithAsync :: Maybe (NonEmpty Whitespace) -- ^ @[\'async\' \<spaces\>]@
   , _unsafeCsWithWith :: [Whitespace] -- ^ @\'with\' \<spaces\>@
   , _unsafeCsWithItems :: CommaSep1 (WithItem v a) -- ^ @\<with_items\>@
   , _unsafeCsWithBody :: Suite v a -- ^ @\<suite\>@
   }
-  deriving (Eq, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn (CompoundStatement v) where
+  annot :: forall a. Lens' (CompoundStatement v a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasExprs ExceptAs where
   _Exprs f (ExceptAs ann e a) = ExceptAs ann <$> f e <*> pure (coerce a)
 
@@ -552,8 +583,8 @@
   _Exprs fun (TryFinally idnt a b c d e f) =
     TryFinally idnt a b <$> _Exprs fun c <*> pure d <*>
     pure e <*> _Exprs fun f
-  _Exprs fun (For idnt a asyncWs b c d e f g) =
-    For idnt a asyncWs b <$> fun c <*> pure d <*> traverse fun e <*>
+  _Exprs fun (For a idnt asyncWs b c d e f g) =
+    For a idnt asyncWs b <$> fun c <*> pure d <*> traverse fun e <*>
     _Exprs fun f <*>
     (traverse._3._Exprs) fun g
   _Exprs fun (ClassDef a decos idnt b c d e) =
diff --git a/src/Language/Python/Syntax/Strings.hs b/src/Language/Python/Syntax/Strings.hs
--- a/src/Language/Python/Syntax/Strings.hs
+++ b/src/Language/Python/Syntax/Strings.hs
@@ -1,4 +1,5 @@
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 {-# language OverloadedStrings #-}
 {-# language LambdaCase #-}
 {-# language TemplateHaskell #-}
@@ -48,13 +49,16 @@
   )
 where
 
-import Control.Lens.Lens (lens)
+import Control.Lens.Lens (Lens', lens)
 import Control.Lens.TH (makeLensesFor)
 import Data.Digit.Octal (OctDigit)
 import Data.Digit.Hexadecimal.MixedCase (HeXDigit(..))
+import Data.Generics.Product.Typed (typed)
 import Data.Maybe (isJust)
 import Data.Text (Text)
+import GHC.Generics (Generic)
 
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Whitespace
 
 -- | Double or single quotation marks?
@@ -68,7 +72,7 @@
 data QuoteType
   = SingleQuote
   | DoubleQuote
-  deriving (Eq, Ord, Show)
+  deriving (Eq, Ord, Show, Generic)
 
 -- | Three pairs of quotations or one?
 --
@@ -81,7 +85,7 @@
 data StringType
   = ShortString
   | LongString
-  deriving (Eq, Ord, Show)
+  deriving (Eq, Ord, Show, Generic)
 
 -- | In Python 3.5, a prefix of @u@ or @U@ is allowed, but doesn't have any
 -- meaning. They exist for backwards compatibility with Python 2.
@@ -90,19 +94,19 @@
 data StringPrefix
   = Prefix_u
   | Prefix_U
-  deriving (Eq, Ord, Show)
+  deriving (Eq, Ord, Show, Generic)
 
 -- | Raw strings are prefixed with either @r@ or @R@.
 data RawStringPrefix
   = Prefix_r
   | Prefix_R
-  deriving (Eq, Ord, Show)
+  deriving (Eq, Ord, Show, Generic)
 
 -- | This prefix indicates it's a bytes literal rather than a string literal.
 data BytesPrefix
   = Prefix_b
   | Prefix_B
-  deriving (Eq, Ord, Show)
+  deriving (Eq, Ord, Show, Generic)
 
 -- | A string of raw bytes can be indicated by a number of prefixes
 data RawBytesPrefix
@@ -114,7 +118,7 @@
   | Prefix_rB
   | Prefix_Rb
   | Prefix_RB
-  deriving (Eq, Ord, Show)
+  deriving (Eq, Ord, Show, Generic)
 
 -- | Most types of 'StringLiteral' have prefixes. Plain old strings may have
 -- an optional prefix, but it is meaningless.
@@ -131,7 +135,7 @@
 -- trailing whitespace.
 data StringLiteral a
   = RawStringLiteral
-  { _stringLiteralAnn :: a
+  { _stringLiteralAnn :: Ann a
   , _unsafeRawStringLiteralPrefix :: RawStringPrefix
   , _stringLiteralStringType :: StringType
   , _stringLiteralQuoteType :: QuoteType
@@ -139,7 +143,7 @@
   , _stringLiteralWhitespace :: [Whitespace]
   }
   | StringLiteral
-  { _stringLiteralAnn :: a
+  { _stringLiteralAnn :: Ann a
   , _unsafeStringLiteralPrefix :: Maybe StringPrefix
   , _stringLiteralStringType :: StringType
   , _stringLiteralQuoteType :: QuoteType
@@ -147,7 +151,7 @@
   , _stringLiteralWhitespace :: [Whitespace]
   }
   | RawBytesLiteral
-  { _stringLiteralAnn :: a
+  { _stringLiteralAnn :: Ann a
   , _unsafeRawBytesLiteralPrefix :: RawBytesPrefix
   , _stringLiteralStringType :: StringType
   , _stringLiteralQuoteType :: QuoteType
@@ -155,15 +159,19 @@
   , _stringLiteralWhitespace :: [Whitespace]
   }
   | BytesLiteral
-  { _stringLiteralAnn :: a
+  { _stringLiteralAnn :: Ann a
   , _unsafeBytesLiteralPrefix :: BytesPrefix
   , _stringLiteralStringType :: StringType
   , _stringLiteralQuoteType :: QuoteType
   , _stringLiteralValue :: [PyChar]
   , _stringLiteralWhitespace :: [Whitespace]
   }
-  deriving (Eq, Ord, Show, Functor, Foldable, Traversable)
+  deriving (Eq, Ord, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn StringLiteral where
+  annot :: forall a. Lens' (StringLiteral a) (Ann a)
+  annot = typed @(Ann a)
+
 instance HasTrailingWhitespace (StringLiteral a) where
   trailingWhitespace =
     lens
@@ -229,7 +237,7 @@
   | Char_esc_v
   -- | Any character
   | Char_lit Char
-  deriving (Eq, Ord, Show)
+  deriving (Eq, Ord, Show, Generic)
 
 -- | Determine whether a 'PyChar' is an escape character or not.
 isEscape :: PyChar -> Bool
diff --git a/src/Language/Python/Syntax/Types.hs b/src/Language/Python/Syntax/Types.hs
--- a/src/Language/Python/Syntax/Types.hs
+++ b/src/Language/Python/Syntax/Types.hs
@@ -1,4 +1,6 @@
 {-# language DataKinds #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 {-# language KindSignatures #-}
 {-# language TemplateHaskell #-}
 
@@ -197,9 +199,13 @@
   )
 where
 
+import Control.Lens.Lens (Lens')
 import Control.Lens.TH (makeLenses)
+import Data.Generics.Product.Typed (typed)
 import Data.List.NonEmpty (NonEmpty)
+import GHC.Generics (Generic)
 
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.CommaSep (Comma, CommaSep, CommaSep1, CommaSep1')
 import Language.Python.Syntax.Expr (Arg, Expr, ListItem, Param, TupleItem)
 import Language.Python.Syntax.Ident (Ident)
@@ -209,7 +215,7 @@
 
 data Fundef v a
   = MkFundef
-  { _fdAnn :: a
+  { _fdAnn :: Ann a
   , _fdDecorators :: [Decorator v a]
   , _fdIndents :: Indents a
   , _fdAsync :: Maybe (NonEmpty Whitespace)
@@ -220,96 +226,128 @@
   , _fdRightParenSpaces :: [Whitespace]
   , _fdReturnType :: Maybe ([Whitespace], Expr v a)
   , _fdBody :: Suite v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''Fundef
 
+instance HasAnn (Fundef v) where
+  annot :: forall a. Lens' (Fundef v a) (Ann a)
+  annot = typed @(Ann a)
+
 data Else v a
   = MkElse
   { _elseIndents :: Indents a
   , _elseElse :: [Whitespace]
   , _elseBody :: Suite v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''Else
 
 data While v a
   = MkWhile
-  { _whileAnn :: a
+  { _whileAnn :: Ann a
   , _whileIndents :: Indents a
   , _whileWhile :: [Whitespace]
   , _whileCond :: Expr v a
   , _whileBody :: Suite v a
   , _whileElse :: Maybe (Else v a)
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''While
 
+instance HasAnn (While v) where
+  annot :: forall a. Lens' (While v a) (Ann a)
+  annot = typed @(Ann a)
+
 data KeywordParam v a
   = MkKeywordParam
-  { _kpAnn :: a
+  { _kpAnn :: Ann a
   , _kpName :: Ident v a
   , _kpType :: Maybe (Colon, Expr v a)
   , _kpEquals :: [Whitespace]
   , _kpExpr :: Expr v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''KeywordParam
 
+instance HasAnn (KeywordParam v) where
+  annot :: forall a. Lens' (KeywordParam v a) (Ann a)
+  annot = typed @(Ann a)
+
 data PositionalParam v a
   = MkPositionalParam
-  { _ppAnn :: a
+  { _ppAnn :: Ann a
   , _ppName :: Ident v a
   , _ppType :: Maybe (Colon, Expr v a)
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''PositionalParam
 
+instance HasAnn (PositionalParam v) where
+  annot :: forall a. Lens' (PositionalParam v a) (Ann a)
+  annot = typed @(Ann a)
+
 data StarParam v a
   = MkStarParam
-  { _spAnn :: a
+  { _spAnn :: Ann a
   , _spWhitespace :: [Whitespace]
   , _spName :: Ident v a
   , _spType :: Maybe (Colon, Expr v a)
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''StarParam
 
+instance HasAnn (StarParam v) where
+  annot :: forall a. Lens' (StarParam v a) (Ann a)
+  annot = typed @(Ann a)
+
 data UnnamedStarParam (v :: [*]) a
   = MkUnnamedStarParam
-  { _uspAnn :: a
+  { _uspAnn :: Ann a
   , _uspWhitespace :: [Whitespace]
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''UnnamedStarParam
 
+instance HasAnn (UnnamedStarParam v) where
+  annot :: forall a. Lens' (UnnamedStarParam v a) (Ann a)
+  annot = typed @(Ann a)
+
 data Call v a
   = MkCall
-  { _callAnn :: a
+  { _callAnn :: Ann a
   , _callFunction :: Expr v a
   , _callLeftParen :: [Whitespace]
   , _callArguments :: Maybe (CommaSep1' (Arg v a))
   , _callRightParen :: [Whitespace]
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''Call
 
+instance HasAnn (Call v) where
+  annot :: forall a. Lens' (Call v a) (Ann a)
+  annot = typed @(Ann a)
+
 data Elif v a
   = MkElif
   { _elifIndents :: Indents a
   , _elifElif :: [Whitespace]
   , _elifCond :: Expr v a
   , _elifBody :: Suite v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''Elif
 
 data If v a
   = MkIf
-  { _ifAnn :: a
+  { _ifAnn :: Ann a
   , _ifIndents :: Indents a
   , _ifIf :: [Whitespace]
   , _ifCond :: Expr v a
   , _ifBody :: Suite v a
   , _ifElifs :: [Elif v a]
   , _ifElse :: Maybe (Else v a)
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''If
 
+instance HasAnn (If v) where
+  annot :: forall a. Lens' (If v a) (Ann a)
+  annot = typed @(Ann a)
+
 data For v a
   = MkFor
-  { _forAnn :: a
+  { _forAnn :: Ann a
   , _forIndents :: Indents a
   , _forAsync :: Maybe (NonEmpty Whitespace)
   , _forFor :: [Whitespace]
@@ -318,15 +356,19 @@
   , _forCollection :: CommaSep1' (Expr v a)
   , _forBody :: Suite v a
   , _forElse :: Maybe (Else v a)
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''For
 
+instance HasAnn (For v) where
+  annot :: forall a. Lens' (For v a) (Ann a)
+  annot = typed @(Ann a)
+
 data Finally v a
   = MkFinally
   { _finallyIndents :: Indents a
   , _finallyFinally :: [Whitespace]
   , _finallyBody :: Suite v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''Finally
 
 data Except v a
@@ -335,93 +377,129 @@
   , _exceptExcept :: [Whitespace]
   , _exceptExceptAs :: Maybe (ExceptAs v a)
   , _exceptBody :: Suite v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''Except
 
 data TryExcept v a
   = MkTryExcept
-  { _teAnn :: a
+  { _teAnn :: Ann a
   , _teIndents :: Indents a
   , _teTry :: [Whitespace]
   , _teBody :: Suite v a
   , _teExcepts :: NonEmpty (Except v a)
   , _teElse :: Maybe (Else v a)
   , _teFinally :: Maybe (Finally v a)
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''TryExcept
 
+instance HasAnn (TryExcept v) where
+  annot :: forall a. Lens' (TryExcept v a) (Ann a)
+  annot = typed @(Ann a)
+
 data TryFinally v a
   = MkTryFinally
-  { _tfAnn :: a
+  { _tfAnn :: Ann a
   , _tfIndents :: Indents a
   , _tfTry :: [Whitespace]
   , _tfBody :: Suite v a
   , _tfFinally :: Finally v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''TryFinally
 
+instance HasAnn (TryFinally v) where
+  annot :: forall a. Lens' (TryFinally v a) (Ann a)
+  annot = typed @(Ann a)
+
 data ClassDef v a
   = MkClassDef
-  { _cdAnn :: a
+  { _cdAnn :: Ann a
   , _cdDecorators :: [Decorator v a]
   , _cdIndents :: Indents a
   , _cdClass :: NonEmpty Whitespace
   , _cdName :: Ident v a
   , _cdArguments :: Maybe ([Whitespace], Maybe (CommaSep1' (Arg v a)), [Whitespace])
   , _cdBody :: Suite v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''ClassDef
 
+instance HasAnn (ClassDef v) where
+  annot :: forall a. Lens' (ClassDef v a) (Ann a)
+  annot = typed @(Ann a)
+
 data With v a
   = MkWith
-  { _withAnn :: a
+  { _withAnn :: Ann a
   , _withIndents :: Indents a
   , _withAsync :: Maybe (NonEmpty Whitespace)
   , _withWith :: [Whitespace]
   , _withItems :: CommaSep1 (WithItem v a)
   , _withBody :: Suite v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''With
 
+instance HasAnn (With v) where
+  annot :: forall a. Lens' (With v a) (Ann a)
+  annot = typed @(Ann a)
+
 data Tuple v a
   = MkTuple
-  { _tupleAnn :: a
+  { _tupleAnn :: Ann a
   , _tupleHead :: TupleItem v a
   , _tupleComma :: Comma
   , _tupleTail :: Maybe (CommaSep1' (TupleItem v a))
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''Tuple
 
+instance HasAnn (Tuple v) where
+  annot :: forall a. Lens' (Tuple v a) (Ann a)
+  annot = typed @(Ann a)
+
 data List v a
   = MkList
-  { _listAnn :: a
+  { _listAnn :: Ann a
   , _listWhitespaceLeft :: [Whitespace]
   , _listBody :: Maybe (CommaSep1' (ListItem v a))
   , _listWhitespaceRight :: [Whitespace]
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''List
 
+instance HasAnn (List v) where
+  annot :: forall a. Lens' (List v a) (Ann a)
+  annot = typed @(Ann a)
+
 data ListUnpack v a
   = MkListUnpack
-  { _listUnpackAnn :: a
+  { _listUnpackAnn :: Ann a
   , _listUnpackParens :: [([Whitespace], [Whitespace])]
   , _listUnpackWhitespace :: [Whitespace]
   , _listUnpackValue :: Expr v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''ListUnpack
 
+instance HasAnn (ListUnpack v) where
+  annot :: forall a. Lens' (ListUnpack v a) (Ann a)
+  annot = typed @(Ann a)
+
 data None (v :: [*]) a
   = MkNone
-  { _noneAnn :: a
+  { _noneAnn :: Ann a
   , _noneWhitespace :: [Whitespace]
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''None
 
+instance HasAnn (None v) where
+  annot :: forall a. Lens' (None v a) (Ann a)
+  annot = typed @(Ann a)
+
 data TupleUnpack v a
   = MkTupleUnpack
-  { _tupleUnpackAnn :: a
+  { _tupleUnpackAnn :: Ann a
   , _tupleUnpackParens :: [([Whitespace], [Whitespace])]
   , _tupleUnpackWhitespace :: [Whitespace]
   , _tupleUnpackValue :: Expr v a
-  } deriving (Eq, Show)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 makeLenses ''TupleUnpack
+
+instance HasAnn (TupleUnpack v) where
+  annot :: forall a. Lens' (TupleUnpack v a) (Ann a)
+  annot = typed @(Ann a)
diff --git a/src/Language/Python/Syntax/Whitespace.hs b/src/Language/Python/Syntax/Whitespace.hs
--- a/src/Language/Python/Syntax/Whitespace.hs
+++ b/src/Language/Python/Syntax/Whitespace.hs
@@ -1,8 +1,9 @@
 {-# language DataKinds #-}
 {-# language GeneralizedNewtypeDeriving, MultiParamTypeClasses, BangPatterns #-}
 {-# language TypeFamilies #-}
-{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
+{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
 {-# language TemplateHaskell #-}
+{-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
 
 {-|
 Module      : Language.Python.Syntax.Whitespace
@@ -34,6 +35,7 @@
 import Control.Lens.TH (makeLenses)
 import Control.Lens.Traversal (Traversal')
 import Data.Deriving (deriveEq1, deriveOrd1)
+import Data.Generics.Product.Typed (typed)
 import Data.Foldable (toList)
 import Data.Function ((&))
 import Data.FingerTree (FingerTree, Measured(..), fromList)
@@ -42,10 +44,12 @@
 import Data.Monoid (Monoid, Endo(..), Dual(..))
 import Data.Semigroup (Semigroup, (<>))
 import GHC.Exts (IsList(..))
+import GHC.Generics (Generic)
 
 import qualified Data.List.NonEmpty as NonEmpty
 
-import Language.Python.Syntax.Comment (Comment)
+import Language.Python.Syntax.Ann
+import Language.Python.Syntax.Comment
 
 -- | A newline is either a carriage return, a line feed, or a carriage return
 -- followed by a line feed.
@@ -117,11 +121,15 @@
 -- whitespace and/or a comment.
 data Blank a
   = Blank
-  { _blankAnn :: a
+  { _blankAnn :: Ann a
   , _blankWhitespaces :: [Whitespace]
   , _blankComment :: Maybe (Comment a)
-  } deriving (Eq, Show, Functor, Foldable, Traversable)
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
+instance HasAnn Blank where
+  annot :: forall a. Lens' (Blank a) (Ann a)
+  annot = typed @(Ann a)
+
 -- | Python has rules regarding the expansion of tabs into spaces and how to
 -- go about computing indentation after this is done.
 --
@@ -194,11 +202,15 @@
 data Indents a
   = Indents
   { _indentsValue :: [Indent]
-  , _indentsAnn :: a
-  } deriving (Eq, Show, Functor, Foldable, Traversable)
+  , _indentsAnn :: Ann a
+  } deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
 
 instance Semigroup a => Semigroup (Indents a) where
   Indents a b <> Indents c d = Indents (a <> c) (b <> d)
+
+instance HasAnn Indents where
+  annot :: forall a. Lens' (Indents a) (Ann a)
+  annot = typed @(Ann a)
 
 makeLenses ''Indents
 deriveEq1 ''Indents
diff --git a/src/Language/Python/Validate/Indentation.hs b/src/Language/Python/Validate/Indentation.hs
--- a/src/Language/Python/Validate/Indentation.hs
+++ b/src/Language/Python/Validate/Indentation.hs
@@ -57,6 +57,7 @@
 
 import Language.Python.Optics
 import Language.Python.Optics.Validated (unvalidated)
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Module
 import Language.Python.Syntax.Expr
@@ -104,20 +105,20 @@
       GreaterThan ->
         case (absolute1Comparison, absolute8Comparison) of
           (GT, GT) -> pure i
-          (GT, _) -> errorVM $ pure (_TabError # a)
-          (_, GT) -> errorVM $ pure (_TabError # a)
+          (GT, _) -> errorVM $ pure (_TabError # getAnn a)
+          (_, GT) -> errorVM $ pure (_TabError # getAnn a)
           (EQ, EQ) -> errorVM $ pure (_ExpectedGreaterThan # (i', i))
-          (_, EQ) -> errorVM $ pure (_TabError # a)
-          (EQ, _) -> errorVM $ pure (_TabError # a)
+          (_, EQ) -> errorVM $ pure (_TabError # getAnn a)
+          (EQ, _) -> errorVM $ pure (_TabError # getAnn a)
           (LT, LT) -> errorVM $ pure (_ExpectedGreaterThan # (i', i))
       EqualTo ->
         case (absolute1Comparison, absolute8Comparison) of
           (EQ, EQ) -> pure i
-          (EQ, _) -> errorVM $ pure (_TabError # a)
-          (_, EQ) -> errorVM $ pure (_TabError # a)
+          (EQ, _) -> errorVM $ pure (_TabError # getAnn a)
+          (_, EQ) -> errorVM $ pure (_TabError # getAnn a)
           (GT, GT) -> errorVM $ pure (_ExpectedEqualTo # (i', i))
-          (_, GT) -> errorVM $ pure (_TabError # a)
-          (GT, _) -> errorVM $ pure (_TabError # a)
+          (_, GT) -> errorVM $ pure (_TabError # getAnn a)
+          (GT, _) -> errorVM $ pure (_TabError # getAnn a)
           (LT, LT) -> errorVM $ pure (_ExpectedEqualTo # (i', i))
 
 setNextIndent :: NextIndent -> [Indent] -> ValidateIndentation e ()
@@ -147,7 +148,7 @@
   -> ValidateIndentation e (Blank a)
 validateBlankIndentation (Blank a ws cmt) =
   if any (\case; Continued{} -> True; _ -> False) ws
-  then errorVM1 $ _EmptyContinuedLine # a
+  then errorVM1 $ _EmptyContinuedLine # getAnn a
   else pure $ Blank a ws cmt
 
 validateBlockIndentation
diff --git a/src/Language/Python/Validate/Scope.hs b/src/Language/Python/Validate/Scope.hs
--- a/src/Language/Python/Validate/Scope.hs
+++ b/src/Language/Python/Validate/Scope.hs
@@ -60,7 +60,7 @@
 import Control.Applicative ((<|>))
 import Control.Lens.Cons (snoc)
 import Control.Lens.Fold ((^..), toListOf, folded)
-import Control.Lens.Getter ((^.), to, getting, use)
+import Control.Lens.Getter ((^.), view, to, getting, use)
 import Control.Lens.Lens (Lens')
 import Control.Lens.Plated (cosmos)
 import Control.Lens.Prism (_Right, _Just)
@@ -87,6 +87,7 @@
 
 import Language.Python.Optics
 import Language.Python.Optics.Validated (unvalidated)
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Statement
 import Language.Python.Syntax.Expr
 import Language.Python.Syntax.Ident
@@ -216,11 +217,11 @@
      traverseOf (traverse._2) validateExprScope mty <*>
      locallyExtendOver
        scGlobalScope
-       ((_identAnn &&& _identValue) name :
-         toListOf (folded.getting paramName.to (_identAnn &&& _identValue)) params)
+       ((view annot_ &&& _identValue) name :
+         toListOf (folded.getting paramName.to (view annot_ &&& _identValue)) params)
        (validateSuiteScope s)) <*
-  extendScope scLocalScope [(_identAnn &&& _identValue) name] <*
-  extendScope scImmediateScope [(_identAnn &&& _identValue) name]
+  extendScope scLocalScope [(view annot_ &&& _identValue) name] <*
+  extendScope scImmediateScope [(view annot_ &&& _identValue) name]
 validateCompoundStatementScope (If idnts a ws1 e b elifs melse) =
   use scLocalScope `bindVM` (\ls ->
   use scImmediateScope `bindVM` (\is ->
@@ -258,7 +259,7 @@
           traverse validateExceptAsScope g <*>
           locallyExtendOver
             scGlobalScope
-            (toListOf (folded.exceptAsName._Just._2.to (_identAnn &&& _identValue)) g)
+            (toListOf (folded.exceptAsName._Just._2.to (view annot_ &&& _identValue)) g)
             (validateSuiteScope h))
        f <*>
      traverseOf (traverse._3) validateSuiteScope k <*>
@@ -288,7 +289,7 @@
     pure d <*>
     traverse validateExprScope e <*>
     (let
-       ls = c ^.. unvalidated.cosmos._Ident.to (_identAnn &&& _identValue)
+       ls = c ^.. unvalidated.cosmos._Ident.to (view annot_ &&& _identValue)
      in
        extendScope scLocalScope ls *>
        extendScope scImmediateScope ls *>
@@ -299,13 +300,13 @@
   traverse validateDecoratorScope decos <*>
   traverseOf (traverse._2.traverse.traverse) validateArgScope d <*>
   validateSuiteScope g <*
-  extendScope scImmediateScope [c ^. to (_identAnn &&& _identValue)]
+  extendScope scImmediateScope [c ^. to (view annot_ &&& _identValue)]
 validateCompoundStatementScope (With a b asyncWs c d e) =
   let
     names =
       d ^..
       folded.unvalidated.to _withItemBinder.folded._2.
-      assignTargets.to (_identAnn &&& _identValue)
+      assignTargets.to (view annot_ &&& _identValue)
   in
     With @(Nub (Scope ': v)) a b asyncWs c <$>
     traverse
@@ -340,7 +341,7 @@
   let
     ls =
       (l : (snd <$> NonEmpty.init rs)) ^..
-      folded.unvalidated.assignTargets.to (_identAnn &&& _identValue)
+      folded.unvalidated.assignTargets.to (view annot_ &&& _identValue)
   in
   Assign a <$>
   validateAssignExprScope l <*>
@@ -353,12 +354,12 @@
   (\l' -> AugAssign a l' aa) <$>
   validateExprScope l <*>
   validateExprScope r
-validateSimpleStatementScope (Global a _ _) = errorVM1 (_FoundGlobal # a)
-validateSimpleStatementScope (Nonlocal a _ _) = errorVM1 (_FoundNonlocal # a)
+validateSimpleStatementScope (Global a _ _) = errorVM1 (_FoundGlobal # getAnn a)
+validateSimpleStatementScope (Nonlocal a _ _) = errorVM1 (_FoundNonlocal # getAnn a)
 validateSimpleStatementScope (Del a ws cs) =
   Del a ws <$
   traverse_
-    (\case; Ident a -> errorVM1 (_DeletedIdent # (a ^. identAnn)); _ -> pure ())
+    (\case; Ident a _ -> errorVM1 (_DeletedIdent # getAnn a); _ -> pure ())
     cs <*>
   traverse validateExprScope cs
 validateSimpleStatementScope s@Pass{} = pure $ unsafeCoerce s
@@ -460,7 +461,7 @@
       validateAssignExprScope c <*>
       validateExprScope e <*
       extendScope scGlobalScope
-        (c ^.. unvalidated.assignTargets.to (_identAnn &&& _identValue))
+        (c ^.. unvalidated.assignTargets.to (view annot_ &&& _identValue))
 
     validateCompIfScope
       :: AsScopeError e a
@@ -627,7 +628,7 @@
   Parens a ws1 <$>
   validateExprScope e <*>
   pure ws2
-validateExprScope (Ident i) = Ident <$> validateIdentScope i
+validateExprScope (Ident a i) = Ident a <$> validateIdentScope i
 validateExprScope (Tuple a b ws d) =
   Tuple a <$>
   validateTupleItemScope b <*>
diff --git a/src/Language/Python/Validate/Syntax.hs b/src/Language/Python/Validate/Syntax.hs
--- a/src/Language/Python/Validate/Syntax.hs
+++ b/src/Language/Python/Validate/Syntax.hs
@@ -2,6 +2,7 @@
 {-# language GeneralizedNewtypeDeriving #-}
 {-# language FlexibleContexts #-}
 {-# language PolyKinds #-}
+{-# language TypeApplications #-}
 {-# language TypeOperators #-}
 {-# language TypeSynonymInstances, FlexibleInstances #-}
 {-# language TemplateHaskell, TypeFamilies, MultiParamTypeClasses #-}
@@ -77,7 +78,6 @@
 import Control.Monad.State (State, put, modify, get, evalState)
 import Control.Monad.Reader (ReaderT, local, ask, runReaderT)
 import Data.Char (isAscii, ord)
-import Data.Coerce (coerce)
 import Data.Foldable (toList, traverse_)
 import Data.Bitraversable (bitraverse)
 import Data.Functor.Compose (Compose(..))
@@ -93,11 +93,13 @@
 
 import Language.Python.Optics
 import Language.Python.Optics.Validated (unvalidated)
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Expr
 import Language.Python.Syntax.Ident
 import Language.Python.Syntax.Import
 import Language.Python.Syntax.Module
+import Language.Python.Syntax.ModuleNames
 import Language.Python.Syntax.Punctuation
 import Language.Python.Syntax.Statement
 import Language.Python.Syntax.Strings
@@ -207,8 +209,8 @@
   => Ident v a
   -> ValidateSyntax e (Ident (Nub (Syntax ': v)) a)
 validateIdentSyntax (MkIdent a name ws)
-  | not (all isAscii name) = errorVM1 (_BadCharacter # (a, name))
-  | null name = errorVM1 (_EmptyIdentifier # a)
+  | not (all isAscii name) = errorVM1 (_BadCharacter # (getAnn a, name))
+  | null name = errorVM1 (_EmptyIdentifier # getAnn a)
   | otherwise =
       bindVM (view inFunction) $ \fi ->
         let
@@ -219,7 +221,7 @@
             else []
         in
           if (name `elem` reserved)
-            then errorVM1 (_IdentifierReservedWord # (a, name))
+            then errorVM1 (_IdentifierReservedWord # (getAnn a, name))
             else pure $ MkIdent a name ws
 
 validateWhitespace
@@ -267,6 +269,13 @@
   -> ValidateSyntax e Comma
 validateComma a (MkComma ws) = MkComma <$> validateWhitespace a ws
 
+validateDot
+  :: (AsSyntaxError e a)
+  => a
+  -> Dot
+  -> ValidateSyntax e Dot
+validateDot a (MkDot ws) = MkDot <$> validateWhitespace a ws
+
 validateColon
   :: (AsSyntaxError e a)
   => a
@@ -278,7 +287,8 @@
   :: AsSyntaxError e a
   => Semicolon a
   -> ValidateSyntax e (Semicolon a)
-validateSemicolon (MkSemicolon a ws) = MkSemicolon a <$> validateWhitespace a ws
+validateSemicolon (MkSemicolon a ws) =
+  MkSemicolon a <$> validateWhitespace (getAnn a) ws
 
 validateEquals
   :: AsSyntaxError e a
@@ -312,7 +322,7 @@
   -> ValidateSyntax e (CompFor (Nub (Syntax ': v)) a)
 validateCompForSyntax (CompFor a b c d e) =
   (\c' -> CompFor a b c' d) <$>
-  liftVM1 (local $ inGenerator .~ True) (validateAssignmentSyntax a c) <*>
+  liftVM1 (local $ inGenerator .~ True) (validateAssignmentSyntax (getAnn a) c) <*>
   validateExprSyntax e
 
 validateCompIfSyntax
@@ -369,18 +379,18 @@
   -> ValidateSyntax e (StringLiteral a)
 validateStringLiteralSyntax (StringLiteral a b c d e f) =
   StringLiteral a b c d <$>
-  traverse (validateStringPyChar a) e <*>
-  validateWhitespace a f
+  traverse (validateStringPyChar $ getAnn a) e <*>
+  validateWhitespace (getAnn a) f
 validateStringLiteralSyntax (BytesLiteral a b c d e f) =
   BytesLiteral a b c d <$>
-  traverse (validateBytesPyChar a) e <*>
-  validateWhitespace a f
+  traverse (validateBytesPyChar $ getAnn a) e <*>
+  validateWhitespace (getAnn a) f
 validateStringLiteralSyntax (RawStringLiteral a b c d e f) =
   RawStringLiteral a b c d e <$>
-  validateWhitespace a f
+  validateWhitespace (getAnn a) f
 validateStringLiteralSyntax (RawBytesLiteral a b c d e f) =
   RawBytesLiteral a b c d e <$>
-  validateWhitespace a f
+  validateWhitespace (getAnn a) f
 
 validateDictItemSyntax
   :: ( AsSyntaxError e a
@@ -394,7 +404,7 @@
   validateExprSyntax d
 validateDictItemSyntax (DictUnpack a b c) =
   DictUnpack a <$>
-  validateWhitespace a b <*>
+  validateWhitespace (getAnn a) b <*>
   validateExprSyntax c
 
 validateSubscriptSyntax
@@ -419,8 +429,8 @@
 validateListItemSyntax (ListItem a b) = ListItem a <$> validateExprSyntax b
 validateListItemSyntax (ListUnpack a b c d) =
   ListUnpack a <$>
-  traverseOf (traverse._2) (validateWhitespace a) b <*>
-  validateWhitespace a c <*>
+  traverseOf (traverse._2) (validateWhitespace $ getAnn a) b <*>
+  validateWhitespace (getAnn a) c <*>
   validateExprSyntax d
 
 validateSetItemSyntax
@@ -432,8 +442,8 @@
 validateSetItemSyntax (SetItem a b) = SetItem a <$> validateExprSyntax b
 validateSetItemSyntax (SetUnpack a b c d) =
   SetUnpack a <$>
-  traverseOf (traverse._2) (validateWhitespace a) b <*>
-  validateWhitespace a c <*>
+  traverseOf (traverse._2) (validateWhitespace $ getAnn a) b <*>
+  validateWhitespace (getAnn a) c <*>
   validateExprSyntax d
 
 validateTupleItemSyntax
@@ -445,8 +455,8 @@
 validateTupleItemSyntax (TupleItem a b) = TupleItem a <$> validateExprSyntax b
 validateTupleItemSyntax (TupleUnpack a b c d) =
   TupleUnpack a <$>
-  traverseOf (traverse._2) (validateWhitespace a) b <*>
-  validateWhitespace a c <*>
+  traverseOf (traverse._2) (validateWhitespace $ getAnn a) b <*>
+  validateWhitespace (getAnn a) c <*>
   validateExprSyntax d
 
 validateExprSyntax
@@ -457,16 +467,16 @@
   -> ValidateSyntax e (Expr (Nub (Syntax ': v)) a)
 validateExprSyntax (Unit a b c) =
   Unit a <$>
-  liftVM1 (local $ inParens .~ True) (validateWhitespace a b) <*>
-  validateWhitespace a c
+  liftVM1 (local $ inParens .~ True) (validateWhitespace (getAnn a) b) <*>
+  validateWhitespace (getAnn a) c
 validateExprSyntax (Lambda a b c d e) =
   let
     paramIdents = c ^.. folded.unvalidated.paramName.identValue
   in
     Lambda a <$>
-    validateWhitespace a b <*>
+    validateWhitespace (getAnn a) b <*>
     validateParamsSyntax True c <*>
-    validateColon a d <*>
+    validateColon (getAnn a) d <*>
     liftVM1
       (local $
        \ctxt ->
@@ -481,29 +491,29 @@
       (validateExprSyntax e)
 validateExprSyntax (Yield a b c) =
   Yield a <$>
-  validateWhitespace a b <*
+  validateWhitespace (getAnn a) b <*
   (ask `bindVM` \ctxt ->
       case _inFunction ctxt of
         Nothing
           | _inGenerator ctxt -> pure ()
-          | otherwise -> errorVM1 (_YieldOutsideGenerator # a)
+          | otherwise -> errorVM1 (_YieldOutsideGenerator # getAnn a)
         Just info ->
           if info^.asyncFunction
-          then errorVM1 $ _YieldInsideCoroutine # a
+          then errorVM1 $ _YieldInsideCoroutine # getAnn a
           else pure ()) <*>
   traverse validateExprSyntax c
 validateExprSyntax (YieldFrom a b c d) =
   YieldFrom a <$>
-  validateWhitespace a b <*>
-  validateWhitespace a c <*
+  validateWhitespace (getAnn a) b <*>
+  validateWhitespace (getAnn a) c <*
   (ask `bindVM` \ctxt ->
       case _inFunction ctxt of
         Nothing
           | _inGenerator ctxt -> pure ()
-          | otherwise -> errorVM1 (_YieldOutsideGenerator # a)
+          | otherwise -> errorVM1 (_YieldOutsideGenerator # getAnn a)
         Just fi ->
           if fi ^. asyncFunction
-          then errorVM1 (_YieldFromInsideCoroutine # a)
+          then errorVM1 (_YieldFromInsideCoroutine # getAnn a)
           else pure ()) <*>
   validateExprSyntax d
 validateExprSyntax (Ternary a b c d e f) =
@@ -517,12 +527,12 @@
   traverse validateSubscriptSyntax d
 validateExprSyntax (Not a ws e) =
   Not a <$>
-  validateWhitespace a ws <*>
+  validateWhitespace (getAnn a) ws <*>
   validateExprSyntax e
 validateExprSyntax (Parens a ws1 e ws2) =
   Parens a ws1 <$>
   liftVM1 (local $ inParens .~ True) (validateExprSyntax e) <*>
-  validateWhitespace a ws2
+  validateWhitespace (getAnn a) ws2
 validateExprSyntax (Bool a b ws) = pure $ Bool a b ws
 validateExprSyntax (UnOp a op expr) =
   UnOp a op <$> validateExprSyntax expr
@@ -544,49 +554,49 @@
   then
     String a <$> traverse validateStringLiteralSyntax strLits
   else
-    errorVM1 (_Can'tJoinStringAndBytes # a)
+    errorVM1 (_Can'tJoinStringAndBytes # getAnn a)
 validateExprSyntax (Int a n ws) = pure $ Int a n ws
 validateExprSyntax (Float a n ws) = pure $ Float a n ws
 validateExprSyntax (Imag a n ws) = pure $ Imag a n ws
-validateExprSyntax (Ident name) = Ident <$> validateIdentSyntax name
+validateExprSyntax (Ident a name) = Ident a <$> validateIdentSyntax name
 validateExprSyntax (List a ws1 exprs ws2) =
   List a ws1 <$>
   liftVM1
     (local $ inParens .~ True)
     (traverseOf (traverse.traverse) validateListItemSyntax exprs) <*>
-  validateWhitespace a ws2
+  validateWhitespace (getAnn a) ws2
 validateExprSyntax (ListComp a ws1 comp ws2) =
   liftVM1
     (local $ inParens .~ True)
     (ListComp a ws1 <$>
      validateComprehensionSyntax validateExprSyntax comp) <*>
-  validateWhitespace a ws2
+  validateWhitespace (getAnn a) ws2
 validateExprSyntax (Generator a comp) =
   Generator a <$> validateComprehensionSyntax validateExprSyntax comp
 validateExprSyntax (Await a ws expr) =
   bindVM ask $ \ctxt ->
   Await a <$>
-  validateWhitespace a ws <*
+  validateWhitespace (getAnn a) ws <*
   (if not $ fromMaybe False (ctxt ^? inFunction._Just.asyncFunction)
-   then errorVM1 $ _AwaitOutsideCoroutine # a
+   then errorVM1 $ _AwaitOutsideCoroutine # getAnn a
    else pure () *>
    if ctxt^.inGenerator
-   then errorVM1 $ _AwaitInsideComprehension # a
+   then errorVM1 $ _AwaitInsideComprehension # getAnn a
    else pure ()) <*>
   validateExprSyntax expr
 validateExprSyntax (Deref a expr ws1 name) =
   Deref a <$>
   validateExprSyntax expr <*>
-  validateWhitespace a ws1 <*>
+  validateWhitespace (getAnn a) ws1 <*>
   validateIdentSyntax name
 validateExprSyntax (Call a expr ws args ws2) =
   Call a <$>
   validateExprSyntax expr <*>
-  liftVM1 (local $ inParens .~ True) (validateWhitespace a ws) <*>
+  liftVM1 (local $ inParens .~ True) (validateWhitespace (getAnn a) ws) <*>
   liftVM1 (local $ inParens .~ True) (traverse validateArgsSyntax args) <*>
-  validateWhitespace a ws2
-validateExprSyntax (None a ws) = None a <$> validateWhitespace a ws
-validateExprSyntax (Ellipsis a ws) = Ellipsis a <$> validateWhitespace a ws
+  validateWhitespace (getAnn a) ws2
+validateExprSyntax (None a ws) = None a <$> validateWhitespace (getAnn a) ws
+validateExprSyntax (Ellipsis a ws) = Ellipsis a <$> validateWhitespace (getAnn a) ws
 validateExprSyntax (BinOp a e1 op e2) =
   BinOp a <$>
   validateExprSyntax e1 <*>
@@ -595,38 +605,38 @@
 validateExprSyntax (Tuple a b comma d) =
   Tuple a <$>
   validateTupleItemSyntax b <*>
-  validateComma a comma <*>
+  validateComma (getAnn a) comma <*>
   traverseOf (traverse.traverse) validateTupleItemSyntax d
 validateExprSyntax (DictComp a ws1 comp ws2) =
   liftVM1
     (local $ inParens .~ True)
     (DictComp a ws1 <$>
      validateComprehensionSyntax dictItem comp) <*>
-  validateWhitespace a ws2
+  validateWhitespace (getAnn a) ws2
   where
-    dictItem (DictUnpack a _ _) = errorVM1 (_InvalidDictUnpacking # a)
+    dictItem (DictUnpack a _ _) = errorVM1 (_InvalidDictUnpacking # getAnn a)
     dictItem a = validateDictItemSyntax a
 validateExprSyntax (Dict a b c d) =
   Dict a b <$>
   liftVM1
     (local $ inParens .~ True)
     (traverseOf (traverse.traverse) validateDictItemSyntax c) <*>
-  validateWhitespace a d
+  validateWhitespace (getAnn a) d
 validateExprSyntax (SetComp a ws1 comp ws2) =
   liftVM1
     (local $ inParens .~ True)
     (SetComp a ws1 <$>
      validateComprehensionSyntax setItem comp) <*>
-  validateWhitespace a ws2
+  validateWhitespace (getAnn a) ws2
   where
-    setItem (SetUnpack a _ _ _) = errorVM1 (_InvalidSetUnpacking # a)
+    setItem (SetUnpack a _ _ _) = errorVM1 (_InvalidSetUnpacking # getAnn a)
     setItem a = validateSetItemSyntax a
 validateExprSyntax (Set a b c d) =
   Set a b <$>
   liftVM1
     (local $ inParens .~ True)
     (traverse validateSetItemSyntax c) <*>
-  validateWhitespace a d
+  validateWhitespace (getAnn a) d
 
 validateBlockSyntax
   :: ( AsSyntaxError e a
@@ -647,11 +657,11 @@
   -> ValidateSyntax e (Suite (Nub (Syntax ': v)) a)
 validateSuiteSyntax (SuiteMany a b c d e) =
   (\b' -> SuiteMany a b' c d) <$>
-  validateColon a b <*>
+  validateColon (getAnn a) b <*>
   validateBlockSyntax e
 validateSuiteSyntax (SuiteOne a b c) =
   SuiteOne a <$>
-  validateColon a b <*>
+  validateColon (getAnn a) b <*>
   validateSmallStatementSyntax c
 
 validateDecoratorSyntax
@@ -662,7 +672,7 @@
   -> ValidateSyntax e (Decorator (Nub (Syntax ': v)) a)
 validateDecoratorSyntax (Decorator a b c d e f g) =
   (\c' d' -> Decorator a b c' d' e f) <$>
-  validateAt a c <*>
+  validateAt (getAnn a) c <*>
   isDecoratorValue d <*>
   traverseOf (traverse._1) validateBlankSyntax g
   where
@@ -672,12 +682,12 @@
 
     isDecoratorValue e@(Call _ a _ _ _) | someDerefs a = pure $ unsafeCoerce e
     isDecoratorValue e | someDerefs e = pure $ unsafeCoerce e
-    isDecoratorValue _ = errorVM1 (_MalformedDecorator # a)
+    isDecoratorValue _ = errorVM1 (_MalformedDecorator # getAnn a)
 
 validateBlankSyntax :: AsSyntaxError e a => Blank a -> ValidateSyntax e (Blank a)
 validateBlankSyntax (Blank a ws cmt) =
   (\ws' -> Blank a ws' cmt) <$>
-  validateWhitespace a ws
+  validateWhitespace (getAnn a) ws
 
 validateCompoundStatementSyntax
   :: forall e v a
@@ -692,13 +702,13 @@
   in
     (\decos' -> Fundef a decos' idnts) <$>
     traverse validateDecoratorSyntax decos <*>
-    traverse (validateWhitespace a) asyncWs <*>
-    validateWhitespace a ws1 <*>
+    traverse (validateWhitespace $ getAnn a) asyncWs <*>
+    validateWhitespace (getAnn a) ws1 <*>
     validateIdentSyntax name <*>
     pure ws2 <*>
     liftVM1 (local $ inParens .~ True) (validateParamsSyntax False params) <*>
     pure ws3 <*>
-    traverse (bitraverse (validateWhitespace a) validateExprSyntax) mty <*>
+    traverse (bitraverse (validateWhitespace $ getAnn a) validateExprSyntax) mty <*>
     localNonlocals id
       (liftVM1
          (local $
@@ -715,7 +725,7 @@
          (validateSuiteSyntax body))
 validateCompoundStatementSyntax (If a idnts ws1 expr body elifs body') =
   If a idnts <$>
-  validateWhitespace a ws1 <*>
+  validateWhitespace (getAnn a) ws1 <*>
   validateExprSyntax expr <*>
   validateSuiteSyntax body <*>
   traverse
@@ -727,56 +737,56 @@
   traverseOf (traverse._3) validateSuiteSyntax body'
 validateCompoundStatementSyntax (While a idnts ws1 expr body els) =
   While a idnts <$>
-  validateWhitespace a ws1 <*>
+  validateWhitespace (getAnn a) ws1 <*>
   validateExprSyntax expr <*>
   liftVM1 (local $ (inFinally .~ False) . (inLoop .~ True)) (validateSuiteSyntax body) <*>
   traverseOf (traverse._3) validateSuiteSyntax els
 validateCompoundStatementSyntax (TryExcept a idnts b e f k l) =
   TryExcept a idnts <$>
-  validateWhitespace a b <*>
+  validateWhitespace (getAnn a) b <*>
   validateSuiteSyntax e <*>
   traverse
     (\(idnts, f, g, j) ->
        (,,,) idnts <$>
-       validateWhitespace a f <*>
+       validateWhitespace (getAnn a) f <*>
        traverse validateExceptAsSyntax g <*>
        validateSuiteSyntax j)
     f <*
   (if anyOf (_init.folded._3) isNothing $ NonEmpty.toList f
-   then errorVM1 $ _DefaultExceptMustBeLast # a
+   then errorVM1 $ _DefaultExceptMustBeLast # getAnn a
    else pure ()) <*>
   traverse
     (\(idnts, x, w) ->
        (,,) idnts <$>
-       validateWhitespace a x <*>
+       validateWhitespace (getAnn a) x <*>
        validateSuiteSyntax w)
     k <*>
   traverse
     (\(idnts, x, w) ->
        (,,) idnts <$>
-       validateWhitespace a x <*>
+       validateWhitespace (getAnn a) x <*>
        liftVM1 (local $ inFinally .~ True) (validateSuiteSyntax w))
     l
 validateCompoundStatementSyntax (TryFinally a idnts b e idnts2 f i) =
   TryFinally a idnts <$>
-  validateWhitespace a b <*>
+  validateWhitespace (getAnn a) b <*>
   validateSuiteSyntax e <*> pure idnts2 <*>
-  validateWhitespace a f <*>
+  validateWhitespace (getAnn a) f <*>
   liftVM1 (local $ inFinally .~ True) (validateSuiteSyntax i)
 validateCompoundStatementSyntax (ClassDef a decos idnts b c d g) =
   liftVM1 (local $ inLoop .~ False) $
   (\decos' -> ClassDef a decos' idnts) <$>
   traverse validateDecoratorSyntax decos <*>
-  validateWhitespace a b <*>
+  validateWhitespace (getAnn a) b <*>
   validateIdentSyntax c <*>
   traverse
     (\(x, y, z) ->
        (,,) <$>
-       validateWhitespace a x <*>
+       validateWhitespace (getAnn a) x <*>
        traverse
          (liftVM1 (local $ inParens .~ True) . validateArgsSyntax)
          y <*>
-       validateWhitespace a z)
+       validateWhitespace (getAnn a) z)
     d <*>
   liftVM1
     (local $ (inClass .~ True) . (inFunction .~ Nothing))
@@ -785,12 +795,12 @@
   bindVM ask $ \ctxt ->
   For a idnts <$
   (if isJust asyncWs && not (fromMaybe False $ ctxt ^? inFunction._Just.asyncFunction)
-   then errorVM1 (_AsyncForOutsideCoroutine # a)
+   then errorVM1 (_AsyncForOutsideCoroutine # getAnn a)
    else pure ()) <*>
-  traverse (validateWhitespace a) asyncWs <*>
-  validateWhitespace a b <*>
-  validateAssignmentSyntax a c <*>
-  validateWhitespace a d <*>
+  traverse (validateWhitespace $ getAnn a) asyncWs <*>
+  validateWhitespace (getAnn a) b <*>
+  validateAssignmentSyntax (getAnn a) c <*>
+  validateWhitespace (getAnn a) d <*>
   traverse validateExprSyntax e <*>
   liftVM1
     (local $ (inFinally .~ False) . (inLoop .~ True))
@@ -798,23 +808,26 @@
   traverse
     (\(idnts, x, w) ->
        (,,) idnts <$>
-       validateWhitespace a x <*>
+       validateWhitespace (getAnn a) x <*>
        validateSuiteSyntax w)
     i
 validateCompoundStatementSyntax (With a b asyncWs c d e) =
   bindVM ask $ \ctxt ->
   With a b <$
   (if isJust asyncWs && not (fromMaybe False $ ctxt ^? inFunction._Just.asyncFunction)
-   then errorVM1 (_AsyncWithOutsideCoroutine # a)
+   then errorVM1 (_AsyncWithOutsideCoroutine # getAnn a)
    else pure ()) <*>
-  traverse (validateWhitespace a) asyncWs <*>
-  validateWhitespace a c <*>
+  traverse (validateWhitespace $ getAnn a) asyncWs <*>
+  validateWhitespace (getAnn a) c <*>
   traverse
     (\(WithItem a b c) ->
         WithItem a <$>
         validateExprSyntax b <*>
         traverse
-          (\(ws, b) -> (,) <$> validateWhitespace a ws <*> validateAssignmentSyntax a b)
+          (\(ws, b) ->
+             (,) <$>
+             validateWhitespace (getAnn a) ws <*>
+             validateAssignmentSyntax (getAnn a) b)
           c)
     d <*>
   validateSuiteSyntax e
@@ -828,13 +841,18 @@
 validateExceptAsSyntax (ExceptAs ann e f) =
   ExceptAs ann <$>
   validateExprSyntax e <*>
-  traverse (\(a, b) -> (,) <$> validateWhitespace ann a <*> validateIdentSyntax b) f
+  traverse
+    (\(a, b) ->
+       (,) <$>
+       validateWhitespace (getAnn ann) a <*>
+       validateIdentSyntax b)
+    f
 
 validateImportAsSyntax
   :: ( AsSyntaxError e a
      , Member Indentation v
      )
-  => (t a -> ValidateSyntax e (t' a))
+  => (t v a -> ValidateSyntax e (t' (Nub (Syntax ': v)) a))
   -> ImportAs t v a
   -> ValidateSyntax e (ImportAs t' (Nub (Syntax ': v)) a)
 validateImportAsSyntax v (ImportAs x a b) =
@@ -843,7 +861,7 @@
   traverse
     (\(c, d) ->
        (,) <$>
-       (c <$ validateWhitespace x (NonEmpty.toList c)) <*>
+       (c <$ validateWhitespace (getAnn x) (NonEmpty.toList c)) <*>
        validateIdentSyntax d)
     b
 
@@ -856,32 +874,63 @@
 validateImportTargetsSyntax (ImportAll a ws) =
   bindVM ask $ \ctxt ->
   if ctxt ^. inClass || has (inFunction._Just) ctxt
-    then errorVM1 $ _WildcardImportInDefinition # a
-    else ImportAll a <$> validateWhitespace a ws
+    then errorVM1 $ _WildcardImportInDefinition # getAnn a
+    else ImportAll a <$> validateWhitespace (getAnn a) ws
 validateImportTargetsSyntax (ImportSome a cs) =
   ImportSome a <$> traverse (validateImportAsSyntax validateIdentSyntax) cs
 validateImportTargetsSyntax (ImportSomeParens a ws1 cs ws2) =
   liftVM1
     (local $ inParens .~ True)
     (ImportSomeParens a <$>
-     validateWhitespace a ws1 <*>
+     validateWhitespace (getAnn a) ws1 <*>
      traverse (validateImportAsSyntax validateIdentSyntax) cs) <*>
-  validateWhitespace a ws2
+  validateWhitespace (getAnn a) ws2
 
+validateModuleNameSyntax
+  :: forall e a v
+   . ( AsSyntaxError e a
+     , Member Indentation v
+     )
+  => ModuleName v a
+  -> ValidateSyntax e (ModuleName (Nub (Syntax ': v)) a)
+validateModuleNameSyntax (ModuleNameOne a b) =
+  ModuleNameOne a <$> validateIdentSyntax b
+validateModuleNameSyntax (ModuleNameMany a b c d) =
+  ModuleNameMany a <$>
+  validateIdentSyntax b <*>
+  validateDot (getAnn a) c <*>
+  validateModuleNameSyntax d
+
+validateRelativeModuleNameSyntax
+  :: forall e a v
+   . ( AsSyntaxError e a
+     , Member Indentation v
+     )
+  => RelativeModuleName v a
+  -> ValidateSyntax e (RelativeModuleName (Nub (Syntax ': v)) a)
+validateRelativeModuleNameSyntax (RelativeWithName ann dots mn) =
+  RelativeWithName ann <$>
+  traverse (validateDot $ getAnn ann) dots <*>
+  validateModuleNameSyntax mn
+validateRelativeModuleNameSyntax (Relative ann dots) =
+  Relative ann <$>
+  traverse (validateDot $ getAnn ann) dots
+
 validateSimpleStatementSyntax
-  :: ( AsSyntaxError e a
+  :: forall e a v
+   . ( AsSyntaxError e a
      , Member Indentation v
      )
   => SimpleStatement v a
   -> ValidateSyntax e (SimpleStatement (Nub (Syntax ': v)) a)
 validateSimpleStatementSyntax (Assert a b c d) =
   Assert a <$>
-  validateWhitespace a b <*>
+  validateWhitespace (getAnn a) b <*>
   validateExprSyntax c <*>
   traverseOf (traverse._2) validateExprSyntax d
 validateSimpleStatementSyntax (Raise a ws f) =
   Raise a <$>
-  validateWhitespace a ws <*>
+  validateWhitespace (getAnn a) ws <*>
   traverse
     (\(b, c) ->
        (,) <$>
@@ -889,7 +938,7 @@
        traverse
          (\(d, e) ->
             (,) <$>
-            validateWhitespace a d <*>
+            validateWhitespace (getAnn a) d <*>
             validateExprSyntax e)
          c)
     f
@@ -898,9 +947,9 @@
     case _inFunction sctxt of
       Just{} ->
         Return a <$>
-        validateWhitespace a ws <*>
+        validateWhitespace (getAnn a) ws <*>
         traverse validateExprSyntax expr
-      _ -> errorVM1 (_ReturnOutsideFunction # a)
+      _ -> errorVM1 (_ReturnOutsideFunction # getAnn a)
 validateSimpleStatementSyntax (Expr a expr) =
   Expr a <$>
   validateExprSyntax expr
@@ -915,15 +964,15 @@
         else []
     in
       Assign a <$>
-      validateAssignmentSyntax a lvalue <*>
+      validateAssignmentSyntax (getAnn a) lvalue <*>
       ((\a b -> case a of; [] -> pure b; a : as -> a :| (snoc as b)) <$>
        traverse
          (\(ws, b) ->
             (,) <$>
-            validateEquals a ws <*>
-            validateAssignmentSyntax a b)
+            validateEquals (getAnn a) ws <*>
+            validateAssignmentSyntax (getAnn a) b)
          (NonEmpty.init rs) <*>
-       (\(ws, b) -> (,) <$> validateEquals a ws <*> validateExprSyntax b)
+       (\(ws, b) -> (,) <$> validateEquals (getAnn a) ws <*> validateExprSyntax b)
          (NonEmpty.last rs)) <*
       liftVM0 (modify (assigns ++))
 validateSimpleStatementSyntax (AugAssign a lvalue aa rvalue) =
@@ -933,29 +982,29 @@
       Ident{} -> validateExprSyntax lvalue
       Deref{} -> validateExprSyntax lvalue
       Subscript{} -> validateExprSyntax lvalue
-      _ -> errorVM1 (_CannotAugAssignTo # (a, lvalue ^. unvalidated))
-    else errorVM1 (_CannotAssignTo # (a, lvalue ^. unvalidated))) <*>
+      _ -> errorVM1 (_CannotAugAssignTo # (getAnn a, lvalue ^. unvalidated))
+    else errorVM1 (_CannotAssignTo # (getAnn a, lvalue ^. unvalidated))) <*>
   pure aa <*>
   validateExprSyntax rvalue
 validateSimpleStatementSyntax (Pass a ws) =
-  Pass a <$> validateWhitespace a ws
+  Pass a <$> validateWhitespace (getAnn a) ws
 validateSimpleStatementSyntax (Break a ws) =
   Break a <$
   (ask `bindVM` \sctxt ->
      if _inLoop sctxt
      then pure ()
-     else errorVM1 (_BreakOutsideLoop # a)) <*>
-  validateWhitespace a ws
+     else errorVM1 (_BreakOutsideLoop # getAnn a)) <*>
+  validateWhitespace (getAnn a) ws
 validateSimpleStatementSyntax (Continue a ws) =
   Continue a <$
   (ask `bindVM` \sctxt ->
      (if _inLoop sctxt
       then pure ()
-      else errorVM1 (_ContinueOutsideLoop # a)) *>
+      else errorVM1 (_ContinueOutsideLoop # getAnn a)) *>
      (if _inFinally sctxt
-      then errorVM1 (_ContinueInsideFinally # a)
+      then errorVM1 (_ContinueInsideFinally # getAnn a)
       else pure ())) <*>
-  validateWhitespace a ws
+  validateWhitespace (getAnn a) ws
 validateSimpleStatementSyntax (Global a ws ids) =
   ask `bindVM` \ctx ->
   let
@@ -968,7 +1017,7 @@
            ival = i ^. getting identValue
          in
          (if ival `elem` params
-          then errorVM1 $ _ParameterMarkedGlobal # (a, ival)
+          then errorVM1 $ _ParameterMarkedGlobal # (getAnn a, ival)
           else pure ()) *>
          validateIdentSyntax i)
       ids
@@ -979,11 +1028,11 @@
      [] -> pure ()
      ids -> traverse_ (\e -> errorVM1 (_NoBindingNonlocal # e)) ids) *>
   case sctxt ^? inFunction._Just.functionParams of
-    Nothing -> errorVM1 (_NonlocalOutsideFunction # a)
+    Nothing -> errorVM1 (_NonlocalOutsideFunction # getAnn a)
     Just params ->
       case intersect params (ids ^.. folded.unvalidated.identValue) of
         [] -> Nonlocal a ws <$> traverse validateIdentSyntax ids
-        bad -> errorVM1 (_ParametersNonlocal # (a, bad))
+        bad -> errorVM1 (_ParametersNonlocal # (getAnn a, bad))
 validateSimpleStatementSyntax (Del a ws ids) =
   Del a ws <$>
   traverse
@@ -991,13 +1040,15 @@
        validateExprSyntax x <*
        if canDelete x
        then pure ()
-       else errorVM1 $ _CannotDelete # (a, x ^. unvalidated))
+       else errorVM1 $ _CannotDelete # (getAnn a, x ^. unvalidated))
     ids
 validateSimpleStatementSyntax (Import a ws mns) =
-  Import a ws <$> traverse (pure . coerce) mns
+  Import @(Nub (Syntax ': v)) a ws <$>
+  traverse (validateImportAsSyntax validateModuleNameSyntax) mns
 validateSimpleStatementSyntax (From a ws1 mn ws2 ts) =
-  From a ws1 (coerce mn) <$>
-  validateWhitespace a ws2 <*>
+  From a ws1 <$>
+  validateRelativeModuleNameSyntax mn <*>
+  validateWhitespace (getAnn a) ws2 <*>
   validateImportTargetsSyntax ts
 
 canDelete :: Expr v a -> Bool
@@ -1116,20 +1167,20 @@
         (PositionalArg a <$> validateExprSyntax expr)
         (go names False False args)
     go names seenKeyword seenUnpack (PositionalArg a expr : args) =
-      when seenKeyword (errorVM1 (_PositionalAfterKeywordArg # (a, expr ^. unvalidated))) *>
-      when seenUnpack (errorVM1 (_PositionalAfterKeywordUnpacking # (a, expr ^. unvalidated))) *>
+      when seenKeyword (errorVM1 (_PositionalAfterKeywordArg # (getAnn a, expr ^. unvalidated))) *>
+      when seenUnpack (errorVM1 (_PositionalAfterKeywordUnpacking # (getAnn a, expr ^. unvalidated))) *>
       go names seenKeyword seenUnpack args
     go names seenKeyword False (StarArg a ws expr : args) =
       liftA2 (:)
-        (StarArg a <$> validateWhitespace a ws <*> validateExprSyntax expr)
+        (StarArg a <$> validateWhitespace (getAnn a) ws <*> validateExprSyntax expr)
         (go names seenKeyword False args)
     go names seenKeyword seenUnpack (StarArg a _ expr : args) =
-      when seenKeyword (errorVM1 (_PositionalAfterKeywordArg # (a, expr ^. unvalidated))) *>
-      when seenUnpack (errorVM1 (_PositionalAfterKeywordUnpacking # (a, expr ^. unvalidated))) *>
+      when seenKeyword (errorVM1 (_PositionalAfterKeywordArg # (getAnn a, expr ^. unvalidated))) *>
+      when seenUnpack (errorVM1 (_PositionalAfterKeywordUnpacking # (getAnn a, expr ^. unvalidated))) *>
       go names seenKeyword seenUnpack args
     go names _ seenUnpack (KeywordArg a name ws2 expr : args)
       | _identValue name `elem` names =
-          errorVM1 (_DuplicateArgument # (a, _identValue name)) <*>
+          errorVM1 (_DuplicateArgument # (getAnn a, _identValue name)) <*>
           validateIdentSyntax name <*>
           go names True seenUnpack args
       | otherwise =
@@ -1142,7 +1193,7 @@
     go names seenKeyword _ (DoubleStarArg a ws expr : args) =
       liftA2 (:)
         (DoubleStarArg a <$>
-         validateWhitespace a ws <*>
+         validateWhitespace (getAnn a) ws <*>
          validateExprSyntax expr)
         (go names seenKeyword True args)
 
@@ -1189,25 +1240,25 @@
         Just b' -> errorVM1 $ _NoKeywordsAfterEmptyStarArg # b'
     go names bsa besa bkw@(HaveSeenKeywordArg False) (PositionalParam a name mty : params)
       | _identValue name `elem` names =
-          errorVM1 (_DuplicateArgument # (a, _identValue name)) <*>
+          errorVM1 (_DuplicateArgument # (getAnn a, _identValue name)) <*>
           validateIdentSyntax name <*>
-          checkTy a mty <*>
+          checkTy (getAnn a) mty <*>
           go (_identValue name:names) bsa besa bkw params
       | otherwise =
           liftA2
             (:)
             (PositionalParam a <$>
              validateIdentSyntax name <*>
-             checkTy a mty)
+             checkTy (getAnn a) mty)
             (go (_identValue name:names) bsa besa bkw params)
     go names (HaveSeenStarArg b) besa bkw (StarParam a _ name mty : params)
       | _identValue name `elem` names =
           if b
           then
-            errorVM1 (_ManyStarredParams # a) <*>
-            errorVM1 (_DuplicateArgument # (a, _identValue name)) <*>
+            errorVM1 (_ManyStarredParams # getAnn a) <*>
+            errorVM1 (_DuplicateArgument # (getAnn a, _identValue name)) <*>
             validateIdentSyntax name <*>
-            checkTy a mty <*>
+            checkTy (getAnn a) mty <*>
             go
               (_identValue name:names)
               (HaveSeenStarArg True)
@@ -1215,9 +1266,9 @@
               bkw
               params
           else
-            errorVM1 (_DuplicateArgument # (a, _identValue name)) <*>
+            errorVM1 (_DuplicateArgument # (getAnn a, _identValue name)) <*>
             validateIdentSyntax name <*>
-            checkTy a mty <*>
+            checkTy (getAnn a) mty <*>
             go
               (_identValue name:names)
               (HaveSeenStarArg True)
@@ -1227,9 +1278,9 @@
       | otherwise =
           if b
           then
-            errorVM1 (_ManyStarredParams # a) <*>
+            errorVM1 (_ManyStarredParams # getAnn a) <*>
             validateIdentSyntax name *>
-            checkTy a mty *>
+            checkTy (getAnn a) mty *>
             go
               (_identValue name:names)
               (HaveSeenStarArg True)
@@ -1238,7 +1289,7 @@
               params
           else
             validateIdentSyntax name *>
-            checkTy a mty *>
+            checkTy (getAnn a) mty *>
             go
               (_identValue name:names)
               (HaveSeenStarArg True)
@@ -1248,18 +1299,18 @@
     go names (HaveSeenStarArg b) _ bkw (UnnamedStarParam a _ : params) =
       if b
       then
-        errorVM1 (_ManyStarredParams # a) <*>
+        errorVM1 (_ManyStarredParams # getAnn a) <*>
         go
           names
           (HaveSeenStarArg True)
-          (HaveSeenEmptyStarArg $ Just a)
+          (HaveSeenEmptyStarArg $ Just $ getAnn a)
           bkw
           params
       else
         go
           names
           (HaveSeenStarArg True)
-          (HaveSeenEmptyStarArg $ Just a)
+          (HaveSeenEmptyStarArg $ Just $ getAnn a)
           bkw
           params
     go names bsa besa bkw@(HaveSeenKeywordArg True) (PositionalParam a name mty : params) =
@@ -1267,22 +1318,22 @@
         name' = _identValue name
         errs =
           foldr (<|)
-            (_PositionalAfterKeywordParam # (a, name') :| [])
-            [_DuplicateArgument # (a, name') | name' `elem` names]
+            (_PositionalAfterKeywordParam # (getAnn a, name') :| [])
+            [_DuplicateArgument # (getAnn a, name') | name' `elem` names]
       in
         errorVM errs <*>
-        checkTy a mty <*>
+        checkTy (getAnn a) mty <*>
         go (name':names) bsa besa bkw params
     go names bsa _ _ (KeywordParam a name mty ws2 expr : params)
       | _identValue name `elem` names =
-          errorVM1 (_DuplicateArgument # (a, _identValue name)) <*>
-          checkTy a mty <*>
+          errorVM1 (_DuplicateArgument # (getAnn a, _identValue name)) <*>
+          checkTy (getAnn a) mty <*>
           go names bsa (HaveSeenEmptyStarArg Nothing) (HaveSeenKeywordArg True) params
       | otherwise =
           liftA2 (:)
             (KeywordParam a <$>
              validateIdentSyntax name <*>
-             checkTy a mty <*>
+             checkTy (getAnn a) mty <*>
              pure ws2 <*>
              validateExprSyntax expr)
             (go
@@ -1293,21 +1344,21 @@
                params)
     go names bsa besa bkw [DoubleStarParam a ws name mty]
       | _identValue name `elem` names =
-          errorVM1 (_DuplicateArgument # (a, _identValue name)) <*>
-          checkTy a mty <*
+          errorVM1 (_DuplicateArgument # (getAnn a, _identValue name)) <*>
+          checkTy (getAnn a) mty <*
           go names bsa besa bkw []
       | otherwise =
           fmap pure $
           DoubleStarParam a ws <$>
           validateIdentSyntax name <*>
-          checkTy a mty <*
+          checkTy (getAnn a) mty <*
           go names bsa besa bkw []
     go names bsa besa bkw (DoubleStarParam a _ name mty : _) =
       (if _identValue name `elem` names
-       then errorVM1 (_DuplicateArgument # (a, _identValue name))
+       then errorVM1 (_DuplicateArgument # (getAnn a, _identValue name))
        else pure ()) *>
-      errorVM1 (_UnexpectedDoubleStarParam # (a, _identValue name)) <*>
-      checkTy a mty <*
+      errorVM1 (_UnexpectedDoubleStarParam # (getAnn a, _identValue name)) <*>
+      checkTy (getAnn a) mty <*
       go names bsa besa bkw []
 
 validateModuleSyntax
diff --git a/test/DSL.hs b/test/DSL.hs
--- a/test/DSL.hs
+++ b/test/DSL.hs
@@ -10,6 +10,7 @@
 import Language.Python.DSL
 import Language.Python.Optics
 import Language.Python.Render (showExpr)
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.CommaSep (CommaSep(..))
 import Language.Python.Syntax.Punctuation (Comma(..))
 import Language.Python.Syntax.Whitespace (Whitespace(..), Indents(..))
@@ -254,7 +255,7 @@
     let
       st = def_ "a" [] [line_ pass_]
 
-    st ^? _Fundef.fdIndents === Just (Indents [] ())
+    st ^? _Fundef.fdIndents === Just (Indents [] (Ann ()))
     over (_Fundef.body_) id st === st
 
 prop_body_2 :: Property
diff --git a/test/LexerParser.hs b/test/LexerParser.hs
--- a/test/LexerParser.hs
+++ b/test/LexerParser.hs
@@ -9,6 +9,7 @@
 import Language.Python.DSL
 import Language.Python.Render
 import Language.Python.Parse (parseModule, parseStatement, parseExpr, parseExprList)
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.CommaSep (CommaSep(..), Comma(..))
 import Language.Python.Syntax.Expr (Expr(..))
 import Language.Python.Syntax.Strings
@@ -288,9 +289,9 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
+          String (Ann ())
             (pure $
-             RawBytesLiteral ()
+             RawBytesLiteral (Ann ())
                Prefix_br
                LongString
                SingleQuote
@@ -306,9 +307,9 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
+          String (Ann ())
             (pure $
-             RawStringLiteral ()
+             RawStringLiteral (Ann ())
                Prefix_r
                LongString
                SingleQuote
@@ -324,9 +325,9 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
+          String (Ann ())
             (pure $
-             RawStringLiteral ()
+             RawStringLiteral (Ann ())
                Prefix_r
                ShortString
                DoubleQuote
@@ -342,9 +343,9 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
+          String (Ann ())
             (pure $
-             RawStringLiteral ()
+             RawStringLiteral (Ann ())
                Prefix_r
                ShortString
                DoubleQuote
@@ -360,9 +361,9 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
+          String (Ann ())
             (pure $
-             RawStringLiteral ()
+             RawStringLiteral (Ann ())
                Prefix_r
                ShortString
                DoubleQuote
@@ -385,9 +386,9 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
+          String (Ann ())
             (pure $
-             RawStringLiteral ()
+             RawStringLiteral (Ann ())
                Prefix_r
                LongString
                DoubleQuote
@@ -403,9 +404,9 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
+          String (Ann ())
             (pure $
-             RawStringLiteral ()
+             RawStringLiteral (Ann ())
                Prefix_r
                LongString
                DoubleQuote
@@ -421,9 +422,9 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
+          String (Ann ())
             (pure $
-             RawStringLiteral ()
+             RawStringLiteral (Ann ())
                Prefix_r
                LongString
                DoubleQuote
@@ -439,9 +440,9 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
+          String (Ann ())
             (pure $
-             RawStringLiteral ()
+             RawStringLiteral (Ann ())
                Prefix_r
                LongString
                DoubleQuote
@@ -460,8 +461,8 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
-            (RawStringLiteral ()
+          String (Ann ())
+            (RawStringLiteral (Ann ())
                Prefix_r
                LongString
                SingleQuote
@@ -484,8 +485,8 @@
   withTests 1 . property $ do
     let str =
           showExpr $
-          String ()
-            (RawStringLiteral ()
+          String (Ann ())
+            (RawStringLiteral (Ann ())
                Prefix_r
                LongString
                SingleQuote
@@ -530,10 +531,10 @@
     let
       e =
         Yield
-        { _unsafeExprAnn = ()
+        { _unsafeExprAnn = Ann ()
         , _unsafeYieldWhitespace = [Space]
         , _unsafeYieldValue =
-            CommaSepMany (Ident (MkIdent () "a" [])) (MkComma [Space]) $
+            CommaSepMany (Ident (Ann ()) (MkIdent (Ann ()) "a" [])) (MkComma [Space]) $
             CommaSepMany (tuple_ [ti_ $ var_ "b"]) (MkComma []) $
             CommaSepNone
         }
diff --git a/test/Optics.hs b/test/Optics.hs
--- a/test/Optics.hs
+++ b/test/Optics.hs
@@ -4,15 +4,16 @@
 import Hedgehog
 
 import Control.Lens.Plated (transformOn)
-import Control.Lens.Setter ((.~))
+import Control.Lens.Setter ((.~), (<>~))
 import Control.Monad.IO.Class (liftIO)
+import Data.Function ((&))
+
 import qualified Data.Text.IO as Text
 
 import Language.Python.Parse (parseModule)
 import Language.Python.Render (showModule)
-import Language.Python.Syntax.Statement (_Statements)
-import Language.Python.Syntax.Whitespace (Whitespace (..))
-import Language.Python.Optics (_Indent)
+import Language.Python.Syntax
+import Language.Python.Optics
 
 import Helpers (shouldBeParseSuccess)
 
@@ -41,3 +42,24 @@
     str' <- liftIO $ Text.readFile "test/files/indent_optics_out2.py"
     showModule
       (transformOn _Statements (_Indent .~ [Space, Space, Space, Space]) tree) === str'
+
+prop_optics_3 :: Property
+prop_optics_3 =
+  withTests 1 . property $ do
+    str <- liftIO $ Text.readFile "test/files/exprs_optics_in1.py"
+
+    tree <- shouldBeParseSuccess parseModule str
+
+    str' <- liftIO $ Text.readFile "test/files/exprs_optics_out1.py"
+    showModule
+      (transformOn (_Statements._Exprs) (_Ident.identValue <>~ "_") tree) === str'
+
+prop_optics_4 :: Property
+prop_optics_4 =
+  withTests 1 . property $ do
+    str <- liftIO $ Text.readFile "test/files/idents_optics_in1.py"
+
+    tree <- shouldBeParseSuccess parseModule str
+
+    str' <- liftIO $ Text.readFile "test/files/idents_optics_out1.py"
+    showModule (tree & _Idents.identValue .~ "b") === str'
diff --git a/test/Scope.hs b/test/Scope.hs
--- a/test/Scope.hs
+++ b/test/Scope.hs
@@ -12,6 +12,7 @@
 import Language.Python.Validate
 import Language.Python.DSL
 import Language.Python.Optics
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.Whitespace
 
 scopeTests :: Group
@@ -46,7 +47,7 @@
           , line_ . return_ $ var_ "a" .+ var_ "b" .+ var_ "c"
           ]
     res <- fullyValidate expr
-    res === Failure (FoundDynamic () (MkIdent () "c" []) :| [])
+    res === Failure (FoundDynamic () (MkIdent (Ann ()) "c" []) :| [])
 
 prop_scope_2 :: Property
 prop_scope_2 =
@@ -73,7 +74,7 @@
           [ line_ . return_ $ var_ "a" .+ var_ "b" .+ var_ "c" ]
     res <- fullyValidate expr
     annotateShow res
-    res === Failure (NotInScope (MkIdent () "c" []) :| [])
+    res === Failure (NotInScope (MkIdent (Ann ()) "c" []) :| [])
 
 prop_scope_4 :: Property
 prop_scope_4 =
@@ -86,7 +87,7 @@
           , line_ $ call_ (var_ "g") []
           ]
     res <- fullyValidate expr
-    res === Failure (NotInScope (MkIdent () "g" []) :| [])
+    res === Failure (NotInScope (MkIdent (Ann ()) "g" []) :| [])
 
 prop_scope_5 :: Property
 prop_scope_5 =
@@ -99,7 +100,7 @@
           ]
     res <- fullyValidate expr
     annotateShow res
-    res === Failure (NotInScope (MkIdent () "c" []) :| [])
+    res === Failure (NotInScope (MkIdent (Ann ()) "c" []) :| [])
 
 prop_scope_6 :: Property
 prop_scope_6 =
@@ -115,7 +116,7 @@
           ]
     res <- fullyValidate expr
     annotateShow res
-    res === Failure (FoundDynamic () (MkIdent () "x" []) :| [])
+    res === Failure (FoundDynamic () (MkIdent (Ann ()) "x" []) :| [])
 
 prop_scope_7 :: Property
 prop_scope_7 =
@@ -131,7 +132,7 @@
           ]
     res <- fullyValidate expr
     annotateShow res
-    res === Failure (FoundDynamic () (MkIdent () "x" []) :| [])
+    res === Failure (FoundDynamic () (MkIdent (Ann ()) "x" []) :| [])
 
 prop_scope_8 :: Property
 prop_scope_8 =
@@ -162,7 +163,7 @@
           ]
     res <- fullyValidate expr
     annotateShow res
-    res === Failure (FoundDynamic () (MkIdent () "x" []) :| [])
+    res === Failure (FoundDynamic () (MkIdent (Ann ()) "x" []) :| [])
 
 prop_scope_10 :: Property
 prop_scope_10 =
@@ -189,4 +190,4 @@
           ]
     res <- fullyValidate st
     annotateShow res
-    res === Failure (BadShadowing (MkIdent () "x" [Space]) :| [])
+    res === Failure (BadShadowing (MkIdent (Ann ()) "x" [Space]) :| [])
diff --git a/test/Syntax.hs b/test/Syntax.hs
--- a/test/Syntax.hs
+++ b/test/Syntax.hs
@@ -13,6 +13,7 @@
 import Language.Python.Optics
 import Language.Python.Parse (parseModule, parseStatement, parseExpr)
 import Language.Python.Render (showStatement, showExpr)
+import Language.Python.Syntax.Ann
 import Language.Python.Syntax.CommaSep
 import Language.Python.Syntax.Expr
 import Language.Python.Syntax.Punctuation
@@ -34,11 +35,11 @@
     let
       e =
         -- lambda *: None
-        Lambda ()
+        Lambda (Ann ())
           [Space]
-          (CommaSepMany (UnnamedStarParam () []) (MkComma []) CommaSepNone)
+          (CommaSepMany (UnnamedStarParam (Ann ()) []) (MkComma []) CommaSepNone)
           (MkColon [Space])
-          (None () [])
+          (None (Ann ()) [])
     res <- syntaxValidateExpr e
     shouldBeFailure res
 
@@ -50,18 +51,18 @@
       e :: Statement '[] ()
       e =
         CompoundStatement .
-        Fundef () []
-          (Indents mempty ())
+        Fundef (Ann ()) []
+          (Indents mempty (Ann ()))
           Nothing
           (pure Space)
             "test"
             [] CommaSepNone [] Nothing .
-          SuiteMany () (MkColon []) Nothing LF $
+          SuiteMany (Ann ()) (MkColon []) Nothing LF $
           Block []
-            (SmallStatement (Indents [i] ()) $
-             MkSmallStatement (Pass () []) [] Nothing Nothing Nothing)
-            [Right . SmallStatement (Indents [i] ()) $
-             MkSmallStatement (Pass () []) [] Nothing Nothing Nothing]
+            (SmallStatement (Indents [i] (Ann ())) $
+             MkSmallStatement (Pass (Ann ()) []) [] Nothing Nothing Nothing)
+            [Right . SmallStatement (Indents [i] (Ann ())) $
+             MkSmallStatement (Pass (Ann ()) []) [] Nothing Nothing Nothing]
     res <- shouldBeParseSuccess parseStatement (showStatement e)
     res' <- shouldBeParseSuccess parseStatement (showStatement res)
     void res === void res'
@@ -80,8 +81,8 @@
     let
       e :: Expr '[] ()
       e =
-        String () . pure $
-        StringLiteral ()
+        String (Ann ()) . pure $
+        StringLiteral (Ann ())
           Nothing
         ShortString SingleQuote
         [Char_lit '\\', Char_lit 'u']
@@ -96,8 +97,8 @@
     let
       e :: Expr '[] ()
       e =
-        String () . pure $
-        StringLiteral ()
+        String (Ann ()) . pure $
+        StringLiteral (Ann ())
           Nothing
         ShortString SingleQuote
         [Char_lit '\\', Char_lit 'x']
diff --git a/test/files/exprs_optics_in1.py b/test/files/exprs_optics_in1.py
new file mode 100644
--- /dev/null
+++ b/test/files/exprs_optics_in1.py
@@ -0,0 +1,3 @@
+for a, b in c:
+    a += 1
+    b += 2
diff --git a/test/files/exprs_optics_out1.py b/test/files/exprs_optics_out1.py
new file mode 100644
--- /dev/null
+++ b/test/files/exprs_optics_out1.py
@@ -0,0 +1,3 @@
+for a_, b_ in c_:
+    a_ += 1
+    b_ += 2
diff --git a/test/files/idents_optics_in1.py b/test/files/idents_optics_in1.py
new file mode 100644
--- /dev/null
+++ b/test/files/idents_optics_in1.py
@@ -0,0 +1,3 @@
+def a(a, a, *a, **a):
+    a += a[a(a,a), a]
+    return a
diff --git a/test/files/idents_optics_out1.py b/test/files/idents_optics_out1.py
new file mode 100644
--- /dev/null
+++ b/test/files/idents_optics_out1.py
@@ -0,0 +1,3 @@
+def b(b, b, *b, **b):
+    b += b[b(b,b), b]
+    return b
