{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedLists #-}
module Language.Rust.Pretty.Resolve (
  Resolve(resolve, resolve', resolveVerbose),
  Issue(..),
  Severity(..),
  ResolveFail(..),
) where
import Language.Rust.Syntax
import Language.Rust.Data.Ident        ( Ident(..), mkIdent )
import Language.Rust.Data.InputStream  ( inputStreamFromString )
import Language.Rust.Data.Position     ( initPos, Spanned(..) )
import Language.Rust.Parser.Lexer      ( lexTokens, lexToken )
import Language.Rust.Parser.ParseMonad ( execParser )
import Control.Exception               ( throw, Exception )
import Control.Monad                   ( when )
import Control.Monad.Trans.RWS
import Data.Dynamic                    ( Dynamic, toDyn, Typeable )
import Data.List                       ( find )
import Data.List.NonEmpty              ( NonEmpty(..) )
import qualified Data.List.NonEmpty as N
import Data.Maybe                      ( fromJust )
import Data.Semigroup                  ( (<>) )
{-# ANN module "HLint: ignore Reduce duplication" #-}
data Severity
  = Clean      
  | Warning    
  | Correction 
  | Error      
  deriving (Eq, Ord, Enum, Bounded, Show)
data Issue = Issue
  { description :: String
  
  
  , severity :: !Severity
  
  , location :: [Dynamic]
  
  
  
  } deriving (Show)
type ResolveM = RWS [Dynamic] [Issue] Severity
logIssue :: String   
         -> Severity 
         -> ResolveM ()
logIssue desc sev = do
  loc <- ask
  tell [Issue desc sev loc]
  modify (max sev)
warn :: String -> ResolveM ()
warn desc = desc `logIssue` Warning
correct :: String -> ResolveM ()
correct desc = desc `logIssue` Correction
err :: a -> String -> ResolveM a
err x desc = (desc `logIssue` Error) *> pure x
scope :: Typeable a => a -> ResolveM b -> ResolveM b
scope x = local (toDyn x :)
data ResolveFail = ResolveFail [Dynamic] String deriving (Typeable)
instance Show ResolveFail where
  showsPrec p (ResolveFail _ msg) = showParen (p >= 11) (showString expl)
    where expl = unwords [ "invalid AST", "(" ++ msg ++ ")" ]
instance Exception ResolveFail
class Resolve a where
  
  
  
  
  
  
  
  
  resolve :: a -> Either ResolveFail a
  resolve x = case runRWS (resolveM x) [] Clean of
                (_, Error, issues) ->
                  let Issue desc _ locs = fromJust (find (\i -> severity i == Error) issues)
                  in Left (ResolveFail locs desc)
                (t, _, _) -> Right t
  
  
  
  
  
  
  resolve' :: a -> a
  resolve' = either throw id . resolve
  
  
  
  resolveVerbose :: a -> (a, Severity, [Issue])
  resolveVerbose x = runRWS (resolveM x) [] Clean
  
  resolveM :: a -> ResolveM a
resolveSourceFile :: (Typeable a, Monoid a) => SourceFile a -> ResolveM (SourceFile a)
resolveSourceFile s@(SourceFile sh as is) = scope s $ do
  sh' <- case sh of
           Just ('[':_) -> err sh "shebang cannot start with `['"
           Just s' | '\n' `elem` s' -> err sh "shebang cannot contain newlines"
           _ -> pure sh
  as' <- traverse (resolveAttr InnerAttr) as
  is' <- traverse (resolveItem ModItem) is
  pure (SourceFile sh' as' is')
instance (Typeable a, Monoid a) => Resolve (SourceFile a) where resolveM = resolveSourceFile
resolveIdent :: Ident -> ResolveM Ident
resolveIdent i@(Ident s r _) =
    scope i $ case toks of
                Right [Spanned (IdentTok i') _]
                   | i /= i' -> err i ("identifier `" ++ s ++ "' does not lex properly")
                   | i `elem` keywords && not r -> do
                      correct ("identifier `" ++ s ++ "' is a keyword")
                      pure i{ raw = True }
                   | otherwise -> pure i
                _ -> err i ("identifier `" ++ s ++ "' does not lex properly")
  where
  keywords = map mkIdent $ words "as box break const continue crate else enum extern false fn for\
                                \ if impl in let loop match mod move mut pub ref return Self self\
                                \ static struct super trait true type unsafe use where while\
                                \ abstract alignof become do final macro offsetof override priv\
                                \ proc pure sizeof typeof unsized virtual yield" 
  
  s' = (if r then "r#" else "") ++ s
  toks = execParser (lexTokens lexToken) (inputStreamFromString s') initPos
instance Resolve Ident where resolveM = resolveIdent
data AttrType
  = EitherAttr 
  | InnerAttr  
  | OuterAttr  
resolveAttr :: (Typeable a, Monoid a) => AttrType -> Attribute a -> ResolveM (Attribute a)
resolveAttr typ s@(SugaredDoc sty inl con x) = scope s $ do 
  sty' <- case (typ, sty) of
            (OuterAttr, Inner) -> correct "inner attribute was turned into outer attribute" *> pure Outer
            (InnerAttr, Outer) -> correct "outer attribute was turned into inner attribute" *> pure Inner
            (_,         sty' ) -> pure sty'
  con' <- case (con, inl, sty') of
            ('/':_, False, Outer) -> correct "the content of an outer (line) doc comment cannot start with a `/'" *> pure (' ':con)
            ('*':_, True, Outer) -> correct "the contents of an outer (inline) doc comment cannot start with a a`*'" *> pure (' ':con)
            (_, False, _) | '\n' `elem` con -> err con "a doc comment that is not inline cannot have multiple lines"
            _ -> pure con
  pure (SugaredDoc sty' inl con' x)
resolveAttr typ a@(Attribute sty p ts x) = scope a $ do
  sty' <- case (typ, sty) of
            (OuterAttr, Inner) -> correct "inner attribute was turned into outer attribute" *> pure Outer
            (InnerAttr, Outer) -> correct "outer attribute was turned into inner attribute" *> pure Inner
            (_,         sty' ) -> pure sty'
  p' <- resolvePath ModPath p
  ts' <- resolveTokenStream ts
  case nextTok ts' of
    Just ModSep -> err () "the first token in the token stream `::' will be considered part of the path"
    _ -> pure ()
  pure (Attribute sty' p' ts' x)
  where
  nextTok :: TokenStream -> Maybe Token
  nextTok (Tree (Token _ t)) = Just t
  nextTok (Tree (Delimited _ d _)) = Just (OpenDelim d)
  nextTok (Stream (s:_)) = nextTok s
  nextTok (Stream []) = Nothing
instance (Typeable a, Monoid a) => Resolve (Attribute a) where resolveM = resolveAttr EitherAttr
resolveLit :: Lit a -> ResolveM (Lit a)
resolveLit = pure
instance Resolve (Lit a) where resolveM = resolveLit
data PathType
  = ModPath
  | UsePath 
  | TypePath
  | ExprPath
  deriving (Eq)
instance Show PathType where
  show ModPath = "mod path"
  show UsePath = "use tree path"
  show TypePath = "type path"
  show ExprPath = "expression path"
resolvePath :: (Typeable a, Monoid a) => PathType -> Path a -> ResolveM (Path a)
resolvePath t p@(Path _ [] _) | t /= UsePath = scope p $ err p "path must have at least one segment"
resolvePath t p@(Path g segs x) = scope p $
    if null [ () | PathSegment _ (Just a) _ <- segs, not (isParamsForPath t a) ]
      then Path g <$> traverse resolveSeg segs <*> pure x 
      else err p "path parameter is not valid for this type of path"
  where
  resolveSeg :: (Typeable a, Monoid a) => PathSegment a -> ResolveM (PathSegment a)
  resolveSeg (PathSegment i a x') = do
    i' <- case i of
            Ident "self" False _ -> pure i
            Ident "Self" False _ -> pure i
            Ident "super" False _ -> pure i
            Ident "crate" False _ -> pure i
            _ -> resolveIdent i
    a' <- traverse resolvePathParameters a
    pure (PathSegment i' a' x')
  isParamsForPath :: PathType -> PathParameters a -> Bool
  isParamsForPath t' AngleBracketed{} = t' `elem` ([TypePath, ExprPath] :: [PathType])
  isParamsForPath t' Parenthesized{}  = t' `elem` ([TypePath] :: [PathType])
instance (Typeable a, Monoid a) => Resolve (Path a) where
  resolveM = resolvePath TypePath
resolvePathParameters :: (Typeable a, Monoid a) => PathParameters a -> ResolveM (PathParameters a)
resolvePathParameters p@(AngleBracketed lts tys bds x) = scope p $ do
  lts' <- traverse resolveLifetime lts
  tys' <- traverse (resolveTy AnyType) tys
  bds' <- traverse (\(i,t) -> (,) <$> resolveIdent i <*> resolveTy NoSumType t) bds
  pure (AngleBracketed lts' tys' bds' x)
resolvePathParameters p@(Parenthesized tys tym x) = scope p $ do
  tys' <- traverse (resolveTy AnyType) tys
  tym' <- traverse (resolveTy NoSumType) tym
  pure (Parenthesized tys' tym' x)
instance (Typeable a, Monoid a) => Resolve (PathParameters a) where resolveM = resolvePathParameters
resolveQSelf :: (Typeable a, Monoid a) => QSelf a -> ResolveM (QSelf a)
resolveQSelf q@(QSelf t p) = scope q (QSelf <$> resolveTy AnyType t <*> pure p)
instance (Typeable a, Monoid a) => Resolve (QSelf a) where resolveM = resolveQSelf
resolveLifetime :: Typeable a => Lifetime a -> ResolveM (Lifetime a)
resolveLifetime l@(Lifetime n _)
  | n == "static" = pure l 
  | n == "_" = pure l 
  | otherwise = scope l (resolveIdent (mkIdent n) *> pure l)
instance Typeable a => Resolve (Lifetime a) where resolveM = resolveLifetime
resolveTraitRef :: (Typeable a, Monoid a) => TraitRef a -> ResolveM (TraitRef a)
resolveTraitRef t@(TraitRef p) = scope t (TraitRef <$> resolvePath TypePath p)
instance (Typeable a, Monoid a) => Resolve (TraitRef a) where resolveM = resolveTraitRef
data TyType
  = AnyType        
  | NoSumType      
  | PrimParenType  
  | NoForType      
resolveTy :: (Typeable a, Monoid a) => TyType -> Ty a -> ResolveM (Ty a)
resolveTy NoSumType     o@(TraitObject b _) | length b > 1 = scope o (correct "added parens around trait object type" *> resolveTy NoSumType (ParenTy o mempty))
resolveTy NoForType     o@TraitObject{} = scope o (correct "added parens around trait object type" *> resolveTy NoForType (ParenTy o mempty))
resolveTy _             o@(TraitObject bds@(TraitTyParamBound{} :| _) x)
  = scope o (TraitObject <$> traverse (resolveTyParamBound ModBound) bds <*> pure x)
resolveTy _             o@TraitObject{} = scope o (err o "first bound in trait object should be a trait bound")
resolveTy PrimParenType p@(ParenTy ty' x) = scope p (ParenTy <$> resolveTy NoSumType ty' <*> pure x)
resolveTy _             p@(ParenTy ty' x) = scope p (ParenTy <$> resolveTy AnyType ty' <*> pure x)
resolveTy PrimParenType t@TupTy{} = scope t (correct "added parens around tuple type" *> resolveTy PrimParenType (ParenTy t mempty))
resolveTy _             t@(TupTy tys x) = scope t (TupTy <$> traverse (resolveTy AnyType) tys <*> pure x)
resolveTy _             i@(ImplTrait bds x) = scope i (ImplTrait <$> traverse (resolveTyParamBound ModBound) bds <*> pure x)
resolveTy PrimParenType p@(PathTy (Just _) _ _) = scope p (correct "added parents around path type" *> resolveTy PrimParenType (ParenTy p mempty))
resolveTy _             p@(PathTy q p'@(Path _ s _) x) = scope p $
  case q of
      Just (QSelf _ i)
        | 0 <= i && i < length s -> PathTy <$> traverse resolveQSelf q <*> resolvePath TypePath p' <*> pure x
        | otherwise              -> err p "index given by QSelf is outside the possible range"
      Nothing                    -> PathTy Nothing <$> resolvePath TypePath p' <*> pure x 
resolveTy NoForType     f@(BareFn _ _ (_:_) _ _) = scope f (correct "added parens around `for' function type" *> resolveTy NoForType (ParenTy f mempty))
resolveTy _             f@(BareFn u a lts fd x) = scope f (BareFn u a <$> traverse resolveLifetimeDef lts <*> resolveFnDecl declTy GeneralArg fd <*> pure x)
  where declTy = if a == C then VarNoSelf else NoSelf
resolveTy _   (Never x) = pure (Never x)
resolveTy _ p@(Ptr mut ty' x) = scope p (Ptr mut <$> resolveTy NoSumType ty' <*> pure x)
resolveTy _ r@(Rptr lt mut ty' x) = scope r (Rptr <$> traverse resolveLifetime lt <*> pure mut <*> resolveTy NoSumType ty' <*> pure x)
resolveTy _ t@(Typeof e x) = scope t (Typeof <$> resolveExpr AnyExpr e <*> pure x)
resolveTy _   (Infer x) = pure (Infer x)
resolveTy _ s@(Slice ty' x) = scope s (Slice <$> resolveTy AnyType ty' <*> pure x)
resolveTy _ a@(Array ty' e x) = scope a (Array <$> resolveTy AnyType ty' <*> resolveExpr AnyExpr e <*> pure x)
resolveTy _ m@(MacTy (Mac p t x) x') = scope m $ do
  p' <- resolvePath TypePath p
  MacTy <$> resolveMac TypePath (Mac p' t x) <*> pure x'
instance (Typeable a, Monoid a) => Resolve (Ty a) where resolveM = resolveTy AnyType
data FnDeclType
  = NoSelf     
  | VarNoSelf  
  | AllowSelf  
  deriving (Eq)
resolveFnDecl :: (Typeable a, Monoid a) => FnDeclType -> ArgType -> FnDecl a -> ResolveM (FnDecl a)
resolveFnDecl fn _  f@(FnDecl (s : _) _ _ _)  | isSelfArg s && fn /= AllowSelf = scope f (err f "self argument is not allowed in this function declaration")
resolveFnDecl _  _  f@(FnDecl (_ : as) _ _ _) | any isSelfArg as = scope f (err f "self arguments must always be the first arguments")
resolveFnDecl fn _  f@(FnDecl _ _ True _)     | fn /= VarNoSelf = scope f (err f "this function declaration cannot be variadic")
resolveFnDecl _  at f@(FnDecl as o v x) = scope f (FnDecl <$> traverse (resolveArg at) as <*> traverse (resolveTy AnyType) o <*> pure v <*> pure x)
isSelfArg :: Arg a -> Bool
isSelfArg Arg{} = False
isSelfArg _ = True
instance (Typeable a, Monoid a) => Resolve (FnDecl a) where resolveM = resolveFnDecl AllowSelf NamedArg
data TyParamBoundType
  = NoneBound          
  | ModBound           
resolveTyParamBound :: (Typeable a, Monoid a) => TyParamBoundType -> TyParamBound a -> ResolveM (TyParamBound a)
resolveTyParamBound _         b@(RegionTyParamBound lt x) =     scope b (RegionTyParamBound <$> resolveLifetime lt <*> pure x)
resolveTyParamBound NoneBound b@(TraitTyParamBound _ Maybe _) = scope b (err b "? trait is not allowed in this type param bound")
resolveTyParamBound _         b@(TraitTyParamBound p t x) =     scope b (TraitTyParamBound <$> resolvePolyTraitRef p <*> pure t <*> pure x)
instance (Typeable a, Monoid a) => Resolve (TyParamBound a) where resolveM = resolveTyParamBound ModBound
data ArgType
  = GeneralArg  
  | NamedArg    
                
resolveArg :: (Typeable a, Monoid a) => ArgType -> Arg a -> ResolveM (Arg a)
resolveArg _ s@SelfValue{} = pure s
resolveArg _ a@(SelfRegion lt m x) = scope a (SelfRegion <$> traverse resolveLifetime lt <*> pure m <*> pure x)
resolveArg _ a@(SelfExplicit t m x) = scope a (SelfExplicit <$> resolveTy AnyType t <*> pure m <*> pure x)
resolveArg NamedArg  a@(Arg Nothing _ _) = scope a (err a "named arguments must have patterns")
resolveArg NamedArg  a@(Arg p t x) = scope a $ do
  when (isSelfAlike a) $
    warn "argument looks like a self argument - did you mean to use 'SelfValue', 'SelfRegion', or 'SelfExplicit'?"
  p' <- traverse resolvePat p
  t' <- resolveTy AnyType t
  pure (Arg p' t' x)
resolveArg GeneralArg a@(Arg p t x) = scope a $ do
  when (isSelfAlike a) $
    warn "argument looks like a self argument - did you mean to use 'SelfValue', 'SelfRegion', or 'SelfExplicit'?"
  
  p' <- case p of
          Nothing -> pure Nothing
          Just WildP{} -> traverse resolvePat p
          Just IdentP{} -> traverse resolvePat p
          Just (RefP WildP{} Immutable _) -> traverse resolvePat p
          Just (RefP (IdentP (ByValue Immutable) _ _ _) Immutable _) -> traverse resolvePat p
          Just (RefP (RefP WildP{} Immutable _) Immutable _) -> traverse resolvePat p
          Just (RefP (RefP (IdentP (ByValue Immutable) _ _ _) Immutable _) Immutable _) -> traverse resolvePat p
          _ -> scope p (err p "this pattern is not allowed for this type of argument")
  t' <- resolveTy AnyType t
  pure (Arg p' t' x)
isSelfAlike :: Arg a -> Bool
isSelfAlike (Arg Nothing (PathTy Nothing (Path False [PathSegment (Ident "self" False _) Nothing _] _) _) _) = True
isSelfAlike (Arg Nothing (Rptr _ _ (PathTy Nothing (Path False [PathSegment (Ident "self" False _) Nothing _] _) _) _) _) = True
isSelfAlike _ = False
instance (Typeable a, Monoid a) => Resolve (Arg a) where resolveM = resolveArg NamedArg
resolvePolyTraitRef :: (Typeable a, Monoid a) => PolyTraitRef a -> ResolveM (PolyTraitRef a)
resolvePolyTraitRef p@(PolyTraitRef lts t x) = scope p $ do
  lts' <- traverse resolveLifetimeDef lts
  t' <- resolveTraitRef t
  pure (PolyTraitRef lts' t' x)
instance (Typeable a, Monoid a) => Resolve (PolyTraitRef a) where resolveM = resolvePolyTraitRef
resolveLifetimeDef :: (Typeable a, Monoid a) => LifetimeDef a -> ResolveM (LifetimeDef a)
resolveLifetimeDef lts@(LifetimeDef as l bds x) = scope lts $ do
  as' <- traverse (resolveAttr OuterAttr) as
  l' <- resolveLifetime l
  bds' <- traverse resolveLifetime bds
  pure (LifetimeDef as' l' bds' x)
instance (Typeable a, Monoid a) => Resolve (LifetimeDef a) where resolveM = resolveLifetimeDef
resolvePat :: (Typeable a, Monoid a) => Pat a -> ResolveM (Pat a)
resolvePat t@(TupleStructP p fs im x) = scope t $ do
  p' <- resolvePath ExprPath p
  fs' <- traverse resolvePat fs
  im' <- case im of
           Nothing -> pure Nothing
           Just i | 0 <= i && i <= length fs -> pure (Just i)
           _ -> err im "index of ... in tuple struct pattern is outside of field range"
  pure (TupleStructP p' fs' im' x)
resolvePat p@(PathP Nothing a x) = scope p (PathP Nothing <$> resolvePath ExprPath a <*> pure x)
resolvePat p@(PathP q@(Just (QSelf _ i)) p'@(Path g s x) x')
  | i < 0 || i >= length s = scope p (err p "index given by QSelf is outside the possible range")
  | i == 0 = scope p (PathP <$> traverse resolveQSelf q <*> resolvePath ExprPath p' <*> pure x)
  | otherwise = scope p $ do
      Path _ tyPSegs   _ <- resolvePath TypePath $ Path g (take i s) mempty
      Path _ exprPSegs _ <- resolvePath ExprPath $ Path False (drop i s) x
      q' <- traverse resolveQSelf q
      pure (PathP q' (Path g (tyPSegs <> exprPSegs) x) x')
resolvePat p@(TupleP ps i x) = scope p $ do
  ps' <- traverse resolvePat ps
  i' <- case i of
          Nothing -> pure Nothing
          Just j | 0 <= j && j <= length ps -> pure i
                 | otherwise -> err i "index of ... in tuple pattern is outside of range"
  pure (TupleP ps' i' x)
resolvePat p@(LitP e x) = scope p (LitP <$> resolveExpr LitExpr e <*> pure x)
resolvePat p@(RangeP l h x) = scope p (RangeP <$> resolveExpr LitOrPathExpr l <*> resolveExpr LitOrPathExpr h <*> pure x)
resolvePat p@(WildP x) = scope p (pure (WildP x))
resolvePat p@(IdentP m i p' x) = scope p (IdentP m <$> resolveIdent i <*> traverse resolvePat p' <*> pure x)
resolvePat p@(StructP p' fs b x) = scope p (StructP <$> resolvePath ExprPath p' <*> traverse resolveFieldPat fs <*> pure b <*> pure x)
resolvePat p@(BoxP p' x) = scope p (BoxP <$> resolvePat p' <*> pure x)
resolvePat p@(RefP p' m x) = scope p (RefP <$> resolvePat p' <*> pure m <*> pure x)
resolvePat p@(SliceP b m a x) = scope p (SliceP <$> traverse resolvePat b <*> traverse resolvePat m <*> traverse resolvePat a <*> pure x)
resolvePat p@(MacP m x) = scope p (MacP <$> resolveMac ExprPath m <*> pure x)
instance (Typeable a, Monoid a) => Resolve (Pat a) where resolveM = resolvePat
resolveFieldPat :: (Typeable a, Monoid a) => FieldPat a -> ResolveM (FieldPat a)
resolveFieldPat f@(FieldPat Nothing p x) = scope f $
    case p of (IdentP _ _ Nothing _)          -> FieldPat Nothing <$> resolvePat p <*> pure x
              (BoxP (IdentP _ _ Nothing _) _) -> FieldPat Nothing <$> resolvePat p <*> pure x
              _                               -> err f "patterns for fields without an identifier must be (possibly box) identifiers"
resolveFieldPat f@(FieldPat i p x) = scope f (FieldPat <$> traverse resolveIdent i <*> resolvePat p <*> pure x)
instance (Typeable a, Monoid a) => Resolve (FieldPat a) where resolveM = resolveFieldPat
data ExprType
  = AnyExpr           
  | LitExpr           
  | LitOrPathExpr     
  | NoStructExpr      
  | NoStructBlockExpr 
  | SemiExpr          
                      
                      
                      
resolveLhsExprP :: (Typeable a, Monoid a) => Int -> ExprType -> Expr a -> ResolveM (Expr a)
resolveLhsExprP p SemiExpr l@Try{}         = resolveExprP p AnyExpr l
resolveLhsExprP p SemiExpr l@FieldAccess{} = resolveExprP p AnyExpr l 
resolveLhsExprP p SemiExpr l@MethodCall{}  = resolveExprP p AnyExpr l
resolveLhsExprP p SemiExpr l@TupField{}    = resolveExprP p AnyExpr l
resolveLhsExprP _ SemiExpr l | isBlockLike l = parenthesize l
resolveLhsExprP p t l = resolveExprP p (lhs t) l
  where
    
    lhs :: ExprType -> ExprType
    lhs LitExpr = error "literal expressions never have a left hand side"
    lhs LitOrPathExpr = error "literal or path expressions never have a left hand side"
    lhs AnyExpr = AnyExpr
    lhs NoStructExpr = NoStructExpr
    lhs NoStructBlockExpr = NoStructBlockExpr
    lhs SemiExpr = AnyExpr
rhs :: ExprType -> ExprType
rhs LitExpr = error "literal expressions never have a right hand side"
rhs LitOrPathExpr = error "literal or path expressions never have a right hand side"
rhs AnyExpr = AnyExpr
rhs NoStructExpr = NoStructExpr
rhs NoStructBlockExpr = NoStructExpr
rhs SemiExpr = AnyExpr
rhs2 :: ExprType -> ExprType
rhs2 LitExpr = error "literal expressions never have a right hand side (2)"
rhs2 LitOrPathExpr = error "literal or path expressions never have a right hand side (2)"
rhs2 AnyExpr = AnyExpr
rhs2 NoStructExpr = NoStructBlockExpr
rhs2 NoStructBlockExpr = NoStructBlockExpr
rhs2 SemiExpr = AnyExpr
resolveExpr :: (Typeable a, Monoid a) => ExprType -> Expr a -> ResolveM (Expr a)
resolveExpr = resolveExprP 0
instance (Typeable a, Monoid a) => Resolve (Expr a) where resolveM = resolveExpr AnyExpr
parenthesize :: (Typeable a, Monoid a) => Expr a -> ResolveM (Expr a)
parenthesize e = do
  correct "added parens around expression"
  e' <- resolveExprP 0 AnyExpr e
  pure (ParenExpr [] e' mempty)
resolveExprP :: (Typeable a, Monoid a) => Int -> ExprType -> Expr a -> ResolveM (Expr a)
resolveExprP p LitExpr l@Lit{} = resolveExprP p AnyExpr l
resolveExprP p LitExpr n@(Unary _ Neg Lit{} _) = resolveExprP p AnyExpr n
resolveExprP _ LitExpr l = scope l (err l "expression is not literal or negated literal")
resolveExprP p LitOrPathExpr l@Lit{} = resolveExprP p AnyExpr l
resolveExprP p LitOrPathExpr n@(Unary _ Neg Lit{} _) = resolveExprP p AnyExpr n
resolveExprP p LitOrPathExpr p'@PathExpr{} = resolveExprP p AnyExpr p'
resolveExprP _ LitOrPathExpr l = scope l (err l "expression is not literal, negated literal, path, or qualified path")
resolveExprP p c b@(Box as e x) = scope b $ parenE (p > 0) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  e' <- resolveExprP 0 (rhs c) e
  pure (Box as' e' x)
resolveExprP p c r@(Ret as me x) = scope r $ parenE (p > 0) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  me' <- traverse (resolveExprP 0 (rhs c)) me
  pure (Ret as' me' x)
resolveExprP p c r@(Yield as me x) = scope r $ parenE (p > 0) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  me' <- traverse (resolveExprP 0 (rhs c)) me
  pure (Yield as' me' x)
resolveExprP p c b@(Break as ml me x) = scope b $ parenE (p > 0) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  ml' <- traverse resolveLbl ml
  me' <- traverse (resolveExprP 0 (rhs c)) me
  pure (Break as' ml' me' x) 
resolveExprP p _ c@(Continue as ml x) = scope c $ parenE (p > 0) $ do 
  as' <- traverse (resolveAttr OuterAttr) as
  ml' <- traverse resolveLbl ml
  pure (Continue as' ml' x)
resolveExprP _ _ c@(Closure _ _ _ (FnDecl _ _ True _) _ _) = scope c (err c "closures can never be variadic")
resolveExprP p c e@(Closure as m cb fn@(FnDecl _ ret _ _) b x) = scope c $
    case (c, ret, b) of
      (NoStructExpr,      Just _, BlockExpr{}) -> parenthesize e
      (NoStructBlockExpr, Just _, BlockExpr{}) -> parenthesize e
      (NoStructExpr,      Just _, _          ) -> parenthesize (Closure as m cb fn (asBlock b) x) 
      (NoStructBlockExpr, Just _, _          ) -> parenthesize (Closure as m cb fn (asBlock b) x)
      (_,                 Just _, BlockExpr{}) -> resolved AnyExpr
      (_,                 Just _, _          ) -> parenthesize (Closure as m cb fn (asBlock b) x)
      _                                         -> resolved (rhs c)
  where
  asBlock ex = BlockExpr [] (Block [NoSemi ex mempty] Normal mempty) mempty
  resolved c' = parenE (p > 0) $ do
    as' <- traverse (resolveAttr OuterAttr) as
    fn' <- resolveFnDecl NoSelf NamedArg fn
    b' <- resolveExprP 0 c' b
    pure (Closure as' m cb fn' b' x)
resolveExprP p c a@(Assign as l r x) = scope a $ parenE (p > 1) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  l' <- resolveLhsExprP 2 c l
  r' <- resolveExprP 1 (rhs c) r
  pure (Assign as' l' r' x)
resolveExprP p c a@(AssignOp as o l r x) = scope a $ parenE (p > 1) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  l' <- resolveLhsExprP 2 c l
  r' <- resolveExprP 1 (rhs c) r
  pure (AssignOp as' o l' r' x)
resolveExprP p c i@(InPlace as l r x) = scope i $ parenE (p > 2) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  l' <- resolveLhsExprP 3 c l
  r' <- resolveExprP 2 (rhs c) r 
  pure (InPlace as' l' r' x)
resolveExprP _ _ r@(Range _ _ Nothing Closed _) = scope r (err r "inclusive ranges must be bounded at the end")
resolveExprP _ _ r@(Range as Nothing Nothing rl x) = scope r $ do
  as' <- traverse (resolveAttr OuterAttr) as
  pure (Range as' Nothing Nothing rl x)
resolveExprP p c a@(Range as (Just l) (Just r) rl x) = scope a $ parenE (p > 3) $ do
  as' <- traverse (resolveAttr OuterAttr) as
 
  l' <- resolveLhsExprP 4 c l
  r' <- resolveExprP 4 (rhs2 c) r
  pure (Range as' (Just l') (Just r') rl x)
resolveExprP p c r@(Range as (Just l) Nothing rl x) = scope r $ parenE (p > 4) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  l' <- resolveLhsExprP 4 c l
  pure (Range as' (Just l') Nothing rl x)
resolveExprP p c a@(Range as Nothing (Just r) rl x) = scope a $ parenE (p > 5) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  r' <- resolveExprP 5 (rhs2 c) r
  pure (Range as' Nothing (Just r') rl x)
resolveExprP p c b@(Binary as o l r x) = scope b $ parenE (p > p') $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  l' <- resolveLhsExprP p' c l
  r' <- resolveExprP (p' + 1) (rhs c) r 
  pure (Binary as' o l' r' x)
  where
  p' = opPrec o
  opPrec :: BinOp -> Int
  opPrec AddOp = 13
  opPrec SubOp = 13
  opPrec MulOp = 14
  opPrec DivOp = 14
  opPrec RemOp = 14
  opPrec AndOp = 7
  opPrec OrOp = 6
  opPrec BitXorOp = 10
  opPrec BitAndOp = 11
  opPrec BitOrOp = 9
  opPrec ShlOp = 12
  opPrec ShrOp = 12
  opPrec EqOp = 8
  opPrec LtOp = 8
  opPrec LeOp = 8
  opPrec NeOp = 8
  opPrec GeOp = 8
  opPrec GtOp = 8
resolveExprP p c a@(Cast as e t x) = scope a $ parenE (p > 15) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  e' <- resolveLhsExprP 15 c e
  t' <- resolveTy NoSumType t
  pure (Cast as' e' t' x)
resolveExprP p c a@(TypeAscription as e t x) = scope a $ parenE (p > 15) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  e' <- resolveLhsExprP 15 c e
  t' <- resolveTy NoSumType t
  pure (TypeAscription as' e' t' x)
resolveExprP p c u@(Unary as o e x) = scope u $ parenE (p > 16) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  e' <- resolveExprP 16 (rhs c) e
  pure (Unary as' o e' x)
resolveExprP p c a@(AddrOf as m e x) = scope a $ parenE (p > 16) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  e' <- resolveExprP 16 (rhs c) e
  pure (AddrOf as' m e' x)
resolveExprP p c a@(Index as e i x) = scope a $ parenE (p > 17) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  e' <- resolveLhsExprP 17 c e
  i' <- resolveExprP 0 AnyExpr i
  pure (Index as' e' i' x)
resolveExprP p SemiExpr t@Try{} = resolveExprP p AnyExpr t
resolveExprP p c t@(Try as e x) = scope t $ parenE (p > 17) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  e' <- resolveLhsExprP 17 c e
  pure (Try as' e' x) 
resolveExprP p c a@(Call as f xs x) = scope a $ parenE (p > 17) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  f' <- resolveLhsExprP 17 c f
  xs' <- traverse (resolveExprP 0 AnyExpr) xs
  pure (Call as' f' xs' x)
resolveExprP p SemiExpr m@MethodCall{} = resolveExprP p AnyExpr m
resolveExprP p c m@(MethodCall as e i mt es x) = scope m $ parenE (p > 17) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  e' <- resolveLhsExprP 17 c e
  i' <- resolveIdent i
  mt' <- case mt of
           Just t -> Just <$> traverse (resolveTy AnyType) t
           Nothing -> pure Nothing
  es' <- traverse (resolveExprP 0 AnyExpr) es
  pure (MethodCall as' e' i' mt' es' x)
resolveExprP p SemiExpr t@TupField{} = resolveExprP p AnyExpr t
resolveExprP p c t@(TupField as e i x) = scope t $ parenE (p > 17) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  e' <- resolveLhsExprP 17 c e
  pure (TupField as' e' i x)
resolveExprP p SemiExpr f@FieldAccess{} = resolveExprP p AnyExpr f
resolveExprP p c f@(FieldAccess as e i x) = scope f $ parenE (p > 17) $ do
  as' <- traverse (resolveAttr OuterAttr) as
  
  e' <- resolveLhsExprP 17 c e
  i' <- resolveIdent i
  pure (FieldAccess as' e' i' x)
resolveExprP _ _ v@(Vec as es x) = scope v $ do
  as' <- traverse (resolveAttr EitherAttr) as
  es' <- traverse (resolveExprP 0 AnyExpr) es
  pure (Vec as' es' x) 
resolveExprP _ _ p@(PathExpr as Nothing p' x) = scope p $ do
  as' <- traverse (resolveAttr OuterAttr) as
  p'' <- resolvePath ExprPath p'
  pure (PathExpr as' Nothing p'' x)
resolveExprP _ _ p@(PathExpr as q@(Just (QSelf _ i)) p'@(Path g s x) x')
  | i < 0 || i >= length s = scope p (err p "index given by QSelf is outside the possible range")
  | i == 0 = scope p $ do
      as' <- traverse (resolveAttr OuterAttr) as
      q' <- traverse resolveQSelf q
      p'' <- resolvePath ExprPath p'
      pure (PathExpr as' q' p'' x)
  | otherwise = scope p $ do
      as' <- traverse (resolveAttr OuterAttr) as
      Path _ tyPSegs   _ <- resolvePath TypePath $ Path g (take i s) mempty
      Path _ exprPSegs _ <- resolvePath ExprPath $ Path False (drop i s) x
      q' <- traverse resolveQSelf q
      pure (PathExpr as' q' (Path g (tyPSegs <> exprPSegs) x) x') 
resolveExprP _ _ i@(Lit as l x) = scope i $ do
  as' <- traverse (resolveAttr OuterAttr) as
  l' <- resolveLit l
  pure (Lit as' l' x)
resolveExprP _ _ a@(Repeat as e r x) = scope a $ do
  as' <- traverse (resolveAttr OuterAttr) as
  e' <- resolveExprP 0 AnyExpr e
  r' <- resolveExprP 0 AnyExpr r
  pure (Repeat as' e' r' x)
resolveExprP _ _ a@(MacExpr as m x) = scope a $ do
  as' <- traverse (resolveAttr OuterAttr) as
  m' <- resolveMac ExprPath m
  pure (MacExpr as' m' x)
resolveExprP _ _ p@(ParenExpr as e x) = scope p $ do
  as' <- traverse (resolveAttr EitherAttr) as
  e' <- resolveExprP 0 AnyExpr e
  pure (ParenExpr as' e' x)
resolveExprP _ _ t@(TupExpr as es x) = scope t $ do
  as' <- traverse (resolveAttr EitherAttr) as
  es' <- traverse (resolveExprP 0 AnyExpr) es
  pure (TupExpr as' es' x)
resolveExprP _ NoStructBlockExpr e@BlockExpr{} = parenthesize e
resolveExprP _ _ l@(BlockExpr as b x) = scope l $ do
  as' <- traverse (resolveAttr EitherAttr) as
  b' <- resolveBlock b
  pure (BlockExpr as' b' x) 
resolveExprP _ NoStructExpr e@Struct{} = parenthesize e
resolveExprP _ NoStructBlockExpr e@Struct{} = parenthesize e
resolveExprP _ _ s@(Struct as p' fs e x) = scope s $ do
  as' <- traverse (resolveAttr OuterAttr) as
  p'' <- resolvePath ExprPath p'
  fs' <- traverse resolveField fs
  e' <- traverse (resolveExprP 0 AnyExpr) e
  pure (Struct as' p'' fs' e' x)
resolveExprP p c i@(If as e b es x) = scope i $ do
  as' <- traverse (resolveAttr OuterAttr) as
  e' <- resolveExprP 0 NoStructExpr e
  b' <- resolveBlock b
  es' <- case es of
           Nothing -> pure Nothing
           (Just If{}) -> traverse (resolveExprP p c) es
           (Just IfLet{}) -> traverse (resolveExprP p c) es
           (Just BlockExpr{}) -> traverse (resolveExprP p c) es
           (Just e'') -> Just <$> resolveExprP p c (BlockExpr [] (Block [NoSemi e'' mempty] Normal mempty) mempty)
  pure (If as' e' b' es' x)
resolveExprP p c i@(IfLet as p' e b es x) = scope i $ do
  as' <- traverse (resolveAttr OuterAttr) as
  p'' <- traverse resolvePat p'
  e' <- resolveExprP 0 NoStructExpr e
  b' <- resolveBlock b
  es' <- case es of
           Nothing -> pure Nothing
           (Just If{}) -> traverse (resolveExprP p c) es
           (Just IfLet{}) -> traverse (resolveExprP p c) es
           (Just BlockExpr{}) -> traverse (resolveExprP p c) es
           (Just e'') -> Just <$> resolveExprP p c (BlockExpr [] (Block [NoSemi e'' mempty] Normal mempty) mempty)
  pure (IfLet as' p'' e' b' es' x)
resolveExprP _ _ w@(While as e b l x) = scope w $ do
  as' <- traverse (resolveAttr EitherAttr) as
  e' <- resolveExprP 0 NoStructExpr e
  b' <- resolveBlock b
  l' <- traverse resolveLbl l
  pure (While as' e' b' l' x)
resolveExprP _ _ w@(WhileLet as p' e b l x) = scope w $ do
  as' <- traverse (resolveAttr EitherAttr) as
  p'' <- traverse resolvePat p'
  e' <- resolveExprP 0 NoStructExpr e
  b' <- resolveBlock b
  l' <- traverse resolveLbl l
  pure (WhileLet as' p'' e' b' l' x)
resolveExprP _ _ f@(ForLoop as p' e b l x) = scope f $ do
  as' <- traverse (resolveAttr EitherAttr) as
  p'' <- resolvePat p'
  e' <- resolveExprP 0 NoStructExpr e
  b' <- resolveBlock b
  l' <- traverse resolveLbl l
  pure (ForLoop as' p'' e' b' l' x)
resolveExprP _ _ o@(Loop as b l x) = scope o $ do
  as' <- traverse (resolveAttr EitherAttr) as
  b' <- resolveBlock b
  l' <- traverse resolveLbl l
  pure (Loop as' b' l' x)
resolveExprP _ _ m@(Match as e ar x) = scope m $ do
  as' <- traverse (resolveAttr EitherAttr) as
  e' <- resolveExprP 0 AnyExpr e
  ar' <- traverse resolveArm ar
  pure (Match as' e' ar' x)
resolveExprP _ _ c@(Catch as b x) = scope c $ do
  as' <- traverse (resolveAttr EitherAttr) as
  b' <- resolveBlock b
  pure (Catch as' b' x) 
isBlockLike :: Expr a -> Bool
isBlockLike If{} = True
isBlockLike IfLet{} = True
isBlockLike Loop{} = True
isBlockLike ForLoop{} = True
isBlockLike While{} = True
isBlockLike WhileLet{} = True
isBlockLike Match{} = True
isBlockLike BlockExpr{} = True
isBlockLike _ = False
resolveLbl :: Typeable a => Label a -> ResolveM (Label a)
resolveLbl l@(Label n _) = scope l (resolveIdent (mkIdent n) *> pure l)
parenE :: (Typeable a, Monoid a) => Bool -> ResolveM (Expr a) -> ResolveM (Expr a)
parenE True e = ParenExpr [] <$> e <*> pure mempty
parenE False e = e
resolveField :: (Typeable a, Monoid a) => Field a -> ResolveM (Field a)
resolveField f@(Field i e x) = scope f $ do
  i' <- resolveIdent i
  e' <- traverse (resolveExpr AnyExpr) e
  pure (Field i' e' x)
instance (Typeable a, Monoid a) => Resolve (Field a) where resolveM = resolveField
resolveArm :: (Typeable a, Monoid a) => Arm a -> ResolveM (Arm a)
resolveArm a@(Arm as ps g b x) = scope a $ do
  as' <- traverse (resolveAttr OuterAttr) as
  ps' <- traverse resolvePat ps
  g' <- traverse (resolveExpr AnyExpr) g
  b' <- resolveExpr SemiExpr b
  pure (Arm as' ps' g' b' x)
instance (Typeable a, Monoid a) => Resolve (Arm a) where resolveM = resolveArm
data StmtType
  = TermStmt 
  | AnyStmt  
resolveStmt :: (Typeable a, Monoid a) => StmtType -> Stmt a -> ResolveM (Stmt a)
resolveStmt _ l@(Local p t i as x) = scope l $ do
  p' <- resolvePat p
  t' <- traverse (resolveTy AnyType) t
  i' <- traverse (resolveExpr AnyExpr) i
  as' <- traverse (resolveAttr OuterAttr) as
  pure (Local p' t' i' as' x)
resolveStmt _ s@(ItemStmt i x) = scope s (ItemStmt <$> resolveItem StmtItem i <*> pure x)
resolveStmt _ s@(Semi e x) | isBlockLike e = scope s (Semi <$> resolveExpr AnyExpr e <*> pure x)
resolveStmt _ s@(Semi e x) = scope s (Semi <$> resolveExpr SemiExpr e <*> pure x)
resolveStmt _ n@(NoSemi e x) | isBlockLike e = scope n (NoSemi <$> resolveExpr AnyExpr e <*> pure x)
resolveStmt AnyStmt  n@(NoSemi e x) = scope n (NoSemi <$> resolveExpr SemiExpr e <*> pure x)
resolveStmt TermStmt n@(NoSemi e x) = scope n (NoSemi <$> resolveExpr AnyExpr (BlockExpr [] (Block [NoSemi e mempty] Normal mempty) mempty) <*> pure x)
resolveStmt _ a@(MacStmt m s as x) = scope a $ do
  m' <- resolveMac ExprPath m
  as' <- traverse (resolveAttr OuterAttr) as
  pure (MacStmt m' s as' x)
instance (Typeable a, Monoid a) => Resolve (Stmt a) where resolveM = resolveStmt AnyStmt
resolveBlock :: (Typeable a, Monoid a) => Block a -> ResolveM (Block a)
resolveBlock b@(Block [] _ _) = pure b
resolveBlock b@(Block (s:ss) r x) = scope b $ do
  ss' <- traverse (resolveStmt TermStmt) (N.init (s :| ss))
  s' <- resolveStmt AnyStmt (N.last (s :| ss))
  pure (Block (ss' ++ [s']) r x)
instance (Typeable a, Monoid a) => Resolve (Block a) where resolveM = resolveBlock
data ItemType
  = StmtItem   
  | ModItem    
resolveVisibility' :: Typeable a => ItemType -> Visibility a -> ResolveM (Visibility a)
resolveVisibility' StmtItem PublicV = pure PublicV
resolveVisibility' StmtItem InheritedV = pure InheritedV
resolveVisibility' StmtItem v = scope v $ err v "statement items can only have public or inherited visibility"
resolveVisibility' ModItem v = pure v
resolveItem :: (Typeable a, Monoid a) => ItemType -> Item a -> ResolveM (Item a)
resolveItem t e@(ExternCrate as v i r x) = scope e $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  r' <- traverse resolveIdent r
  pure (ExternCrate as' v' i' r' x)
resolveItem t u@(Use as v p x) = scope u $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  p' <- resolveUseTree p
  pure (Use as' v' p' x)
resolveItem t s@(Static as v i t' m e x) = scope s $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  t'' <- resolveTy AnyType t'
  e' <- resolveExpr AnyExpr e
  pure (Static as' v' i' t'' m e' x)
resolveItem t c@(ConstItem as v i t' e x) = scope c $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  t'' <- resolveTy AnyType t'
  e' <- resolveExpr AnyExpr e
  pure (ConstItem as' v' i' t'' e' x)
resolveItem t f@(Fn as v i d u c a g b x) = scope f $ do
  as' <- traverse (resolveAttr EitherAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  d' <- resolveFnDecl NoSelf NamedArg d
  g' <- resolveGenerics g
  b' <- resolveBlock b
  pure (Fn as' v' i' d' u c a g' b' x)
resolveItem t m@(Mod as v i (Just is) x) = scope m $ do
  as' <- traverse (resolveAttr EitherAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  is' <- traverse (resolveItem ModItem) is
  pure (Mod as' v' i' (Just is') x)
resolveItem t m@(Mod as v i Nothing x) = scope m $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  pure (Mod as' v' i' Nothing x)
resolveItem t m@(ForeignMod as v a is x) = scope m $ do
  as' <- traverse (resolveAttr EitherAttr) as
  v' <- resolveVisibility' t v
  is' <- traverse (resolveForeignItem a) is
  pure (ForeignMod as' v' a is' x)
resolveItem t a@(TyAlias as v i t' g x) = scope a $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  t'' <- resolveTy AnyType t'
  g' <- resolveGenerics g
  pure (TyAlias as' v' i' t'' g' x)
resolveItem t e@(Enum as v i vs g x) = scope e $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  vs' <- traverse resolveVariant vs
  g' <- resolveGenerics g
  pure (Enum as' v' i' vs' g' x)
  
resolveItem t s@(StructItem as v i vd g x) = scope s $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  vd' <- resolveVariantData vd
  g' <- resolveGenerics g
  pure (StructItem as' v' i' vd' g' x)
resolveItem t u@(Union as v i vd g x) = scope u $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  vd' <- resolveVariantData vd
  g' <- resolveGenerics g
  pure (Union as' v' i' vd' g' x)
resolveItem t r@(Trait as v i a u g bd is x) = scope r $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  g' <- resolveGenerics g
  bd' <- traverse (resolveTyParamBound NoneBound) bd
  is' <- traverse resolveTraitItem is
  pure (Trait as' v' i' a u g' bd' is' x)
resolveItem t r@(TraitAlias as v i g bd x) = scope r $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility' t v
  i' <- resolveIdent i
  g' <- resolveGenerics g
  bd' <- traverse (resolveTyParamBound NoneBound) bd
  pure (TraitAlias as' v' i' g' bd' x)
resolveItem t i'@(Impl as v d u i g mt t' is x) = scope i' $ do
  as' <- traverse (resolveAttr EitherAttr) as
  v' <- resolveVisibility' t v
  g' <- resolveGenerics g
  mt' <- traverse resolveTraitRef mt
  t'' <- case mt of
           Nothing -> resolveTy PrimParenType t'
           Just _ -> resolveTy AnyType t'
  is' <- traverse resolveImplItem is
  pure (Impl as' v' d u i g' mt' t'' is' x)
resolveItem StmtItem m@MacItem{} = scope m (err m "macro items cannot be in statement items")
resolveItem _ a@(MacItem as i m x) = scope a $ do
  as' <- traverse (resolveAttr OuterAttr) as
  i' <- traverse resolveIdent i
  m' <- resolveMac ExprPath m
  pure (MacItem as' i' m' x)
resolveItem _ m@(MacroDef as i ts x) = scope m $ do
  as' <- traverse (resolveAttr OuterAttr) as
  i' <- resolveIdent i
  ts' <- resolveTokenStream ts
  pure (MacroDef as' i' ts' x)
instance (Typeable a, Monoid a) => Resolve (Item a) where resolveM = resolveItem ModItem
resolveForeignItem :: (Typeable a, Monoid a) => Abi -> ForeignItem a -> ResolveM (ForeignItem a)
resolveForeignItem a f@(ForeignFn as v i fn g x) = scope f $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility v
  i' <- resolveIdent i
  fn' <- resolveFnDecl (case a of { C -> VarNoSelf; _ -> NoSelf }) NamedArg fn
  g' <- resolveGenerics g
  pure (ForeignFn as' v' i' fn' g' x)
resolveForeignItem _ f@(ForeignStatic as v i t m x) = scope f $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility v
  i' <- resolveIdent i
  t' <- resolveTy AnyType t
  pure (ForeignStatic as' v' i' t' m x)
resolveForeignItem _ f@(ForeignTy as v i x) = scope f $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility v
  i' <- resolveIdent i
  pure (ForeignTy as' v' i' x)
instance (Typeable a, Monoid a) => Resolve (ForeignItem a) where resolveM = resolveForeignItem C
resolveWhereClause :: (Typeable a, Monoid a) => WhereClause a -> ResolveM (WhereClause a)
resolveWhereClause w@(WhereClause p x) = scope w (WhereClause <$> traverse resolveWherePredicate p <*> pure x)
instance (Typeable a, Monoid a) => Resolve (WhereClause a) where resolveM = resolveWhereClause
resolveGenerics :: (Typeable a, Monoid a) => Generics a -> ResolveM (Generics a)
resolveGenerics g@(Generics lts typ wc x) = scope g $ do
  lts' <- traverse resolveLifetimeDef lts
  typ' <- traverse resolveTyParam typ
  wc' <- resolveWhereClause wc
  pure (Generics lts' typ' wc' x)
instance (Typeable a, Monoid a) => Resolve (Generics a) where resolveM = resolveGenerics
resolveTyParam :: (Typeable a, Monoid a) => TyParam a -> ResolveM (TyParam a)
resolveTyParam p@(TyParam as i bds t x) = scope p $ do
  as' <- traverse (resolveAttr OuterAttr) as
  i' <- resolveIdent i
  bds' <- traverse (resolveTyParamBound ModBound) bds
  t' <- traverse (resolveTy AnyType) t
  pure (TyParam as' i' bds' t' x)
instance (Typeable a, Monoid a) => Resolve (TyParam a) where resolveM = resolveTyParam
data StructFieldType
  = IdentStructField  
  | BareStructField   
resolveVariant :: (Typeable a, Monoid a) => Variant a -> ResolveM (Variant a)
resolveVariant v@(Variant i as n e x) = scope v $ do
  i' <- resolveIdent i
  as' <- traverse (resolveAttr OuterAttr) as
  n' <- resolveVariantData n
  e' <- traverse (resolveExpr AnyExpr) e
  pure (Variant i' as' n' e' x)
instance (Typeable a, Monoid a) => Resolve (Variant a) where resolveM = resolveVariant
resolveVariantData :: (Typeable a, Monoid a) => VariantData a -> ResolveM (VariantData a)
resolveVariantData v@(StructD fs x) = scope v (StructD <$> traverse (resolveStructField IdentStructField) fs <*> pure x)
resolveVariantData v@(TupleD fs x) = scope v (TupleD <$> traverse (resolveStructField BareStructField) fs <*> pure x)
resolveVariantData   (UnitD x) = pure (UnitD x)
instance (Typeable a, Monoid a) => Resolve (VariantData a) where resolveM = resolveVariantData
resolveStructField :: (Typeable a, Monoid a) => StructFieldType -> StructField a -> ResolveM (StructField a)
resolveStructField IdentStructField s@(StructField Nothing _ _ _ _) = scope s $ err s "struct field needs an identifier"
resolveStructField IdentStructField s@(StructField (Just i) v t as x) = scope s $ do
  i' <- resolveIdent i
  v' <- resolveVisibility v
  t' <- resolveTy AnyType t
  as' <- traverse (resolveAttr OuterAttr) as
  pure (StructField (Just i') v' t' as' x)
resolveStructField BareStructField s@(StructField (Just _) _ _ _ _) = scope s $ err s "tuple-struct field cannot have an identifier"
resolveStructField BareStructField s@(StructField Nothing v t as x) = scope s $ do
  v' <- resolveVisibility v
  t' <- resolveTy AnyType t
  as' <- traverse (resolveAttr OuterAttr) as
  pure (StructField Nothing v' t' as' x)
instance (Typeable a, Monoid a) => Resolve (StructField a) where resolveM = resolveStructField IdentStructField
resolveWherePredicate :: (Typeable a, Monoid a) => WherePredicate a -> ResolveM (WherePredicate a)
resolveWherePredicate p@(EqPredicate t1 t2 x) = scope p (EqPredicate <$> resolveTy NoForType t1 <*> resolveTy AnyType t2 <*> pure x)
resolveWherePredicate p@(RegionPredicate l ls x) = scope p $ do
  l' <- resolveLifetime l
  ls' <- traverse resolveLifetime ls
  pure (RegionPredicate l' ls' x)
resolveWherePredicate p@(BoundPredicate lts t bds x) = scope p $ do
  lts' <- traverse resolveLifetimeDef lts
  t' <- resolveTy NoForType t
  bds' <- traverse (resolveTyParamBound ModBound) bds
  pure (BoundPredicate lts' t' bds' x)
instance (Typeable a, Monoid a) => Resolve (WherePredicate a) where resolveM = resolveWherePredicate
resolveTraitItem :: (Typeable a, Monoid a) => TraitItem a -> ResolveM (TraitItem a)
resolveTraitItem n@(ConstT as i t e x) = scope n $ do
  as' <- traverse (resolveAttr OuterAttr) as
  i' <- resolveIdent i
  t' <- resolveTy AnyType t
  e' <- traverse (resolveExpr AnyExpr) e
  pure (ConstT as' i' t' e' x)
resolveTraitItem n@(MethodT as i g m b x) = scope n $ do
  as' <- traverse (resolveAttr OuterAttr) as
  i' <- resolveIdent i
  g' <- resolveGenerics g
  m' <- resolveMethodSig GeneralArg m 
  b' <- traverse resolveBlock b
  pure (MethodT as' i' g' m' b' x)
resolveTraitItem n@(TypeT as i bd t x) = scope n $ do
  as' <- traverse (resolveAttr OuterAttr) as
  i' <- resolveIdent i
  bd' <- traverse (resolveTyParamBound ModBound) bd
  t' <- traverse (resolveTy AnyType) t
  pure (TypeT as' i' bd' t' x)
resolveTraitItem n@(MacroT as m x) = scope n $ do
  as' <- traverse (resolveAttr OuterAttr) as
  m' <- resolveMac ModPath m
  pure (MacroT as' m' x)
instance (Typeable a, Monoid a) => Resolve (TraitItem a) where resolveM = resolveTraitItem
resolveImplItem :: (Typeable a, Monoid a) => ImplItem a -> ResolveM (ImplItem a)
resolveImplItem n@(ConstI as v d i t e x) = scope n $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility v
  i' <- resolveIdent i
  t' <- resolveTy AnyType t
  e' <- resolveExpr AnyExpr e
  pure (ConstI as' v' d i' t' e' x)
resolveImplItem n@(MethodI as v d i g m b x) = scope n $ do
  as' <- traverse (resolveAttr EitherAttr) as
  v' <- resolveVisibility v
  i' <- resolveIdent i
  g' <- resolveGenerics g
  m' <- resolveMethodSig NamedArg m 
  b' <- resolveBlock b
  pure (MethodI as' v' d i' g' m' b' x)
resolveImplItem n@(TypeI as v d i t x) = scope n $ do
  as' <- traverse (resolveAttr OuterAttr) as
  v' <- resolveVisibility v
  i' <- resolveIdent i
  t' <- resolveTy AnyType t
  pure (TypeI as' v' d i' t' x)
resolveImplItem n@(MacroI as d m x) = scope n $ do
  as' <- traverse (resolveAttr OuterAttr) as
  m' <- resolveMac ModPath m
  pure (MacroI as' d m' x)
instance (Typeable a, Monoid a) => Resolve (ImplItem a) where resolveM = resolveImplItem
resolveVisibility :: (Typeable a, Monoid a) => Visibility a -> ResolveM (Visibility a)
resolveVisibility PublicV = pure PublicV
resolveVisibility InheritedV = pure InheritedV
resolveVisibility CrateV = pure CrateV
resolveVisibility v@(RestrictedV p) = scope v (RestrictedV <$> resolvePath ModPath p)
instance (Typeable a, Monoid a) => Resolve (Visibility a) where resolveM = resolveVisibility
resolveMethodSig :: (Typeable a, Monoid a) => ArgType -> MethodSig a -> ResolveM (MethodSig a)
resolveMethodSig at m@(MethodSig u c a f) = scope m (MethodSig u c a <$> resolveFnDecl AllowSelf at f)
instance (Typeable a, Monoid a) => Resolve (MethodSig a) where resolveM = resolveMethodSig NamedArg
resolveUseTree :: (Typeable a, Monoid a) => UseTree a -> ResolveM (UseTree a)
resolveUseTree v@(UseTreeSimple p i x) = scope v $ do
  p' <- resolvePath ModPath p 
  i' <- traverse resolveIdent i
  pure (UseTreeSimple p' i' x)
resolveUseTree v@(UseTreeGlob p x) = scope v $ do
  p' <- resolvePath UsePath p 
  pure (UseTreeGlob p' x) 
resolveUseTree v@(UseTreeNested p ns x) = scope v $ do
  p' <- resolvePath UsePath p
  ns' <- traverse resolveUseTree ns
  pure (UseTreeNested p' ns' x)
instance (Typeable a, Monoid a) => Resolve (UseTree a) where resolveM = resolveUseTree
resolveMac :: (Typeable a, Monoid a) => PathType -> Mac a -> ResolveM (Mac a)
resolveMac t m@(Mac p ts x) = scope m (Mac <$> resolvePath t p <*> resolveTokenStream ts <*> pure x)
instance (Typeable a, Monoid a) => Resolve (Mac a) where
  resolveM m@(Mac p ts x) = scope m (Mac <$> resolveM p <*> resolveTokenStream ts <*> pure x) 
resolveTt :: TokenTree -> ResolveM TokenTree
resolveTt t@(Token _ (OpenDelim _)) = scope t (err t "open delimiter is not allowed as a token in a token tree")
resolveTt t@(Token _ (CloseDelim _)) = scope t (err t "close delimiter is not allowed as a token in a token tree")
resolveTt t@Token{} = pure t
resolveTt t@(Delimited s d ts) = scope t (Delimited s d <$> resolveTokenStream ts)
instance Resolve TokenTree where resolveM = resolveTt
resolveTokenStream :: TokenStream -> ResolveM TokenStream
resolveTokenStream s@(Tree tt) = scope s (Tree <$> resolveTt tt)
resolveTokenStream s@(Stream ts) = scope s (Stream <$> mapM resolveTokenStream ts)
instance Resolve TokenStream where resolveM = resolveTokenStream