From 0fe62673056f008c58ee1ee44af9a38e6fe94ae3 Mon Sep 17 00:00:00 2001
From: Matthew Pickering <matthewtpickering@gmail.com>
Date: Thu, 27 Mar 2025 13:44:02 +0000
Subject: [PATCH] Implement v2-outdated command for cabal-install

This commit updates the outdated command to the new v2 architecture:

- Transform the old `outdated` command into a new v2-style command `v2-outdated`
- Support three modes of operation:
  - Check for outdated dependencies in v1-style freeze file
  - Check for outdated dependencies in project context (cabal.project & cabal.project.freeze)
  - Check for outdated dependencies in local packages

Since the `cabal outdated` command now supports the v2-architecture, you
can request to run the `v2-outdated` command on any target.

I also introduced the `resolveTargetsFromLocalPackages` which resolves
which local packages targets refer to without having to run the solver.
This will be useful for `cabal check` as well.

A change in behaviour from before is that the package description is
flattened, so all bounds will be warned about rather than those in
conditional branches being ignored.

Fixes #8283
---
 .../src/Distribution/Utils/Generic.hs         |   5 +
 Cabal/src/Distribution/Simple/Utils.hs        |   1 +
 .../Solver/Types/ProjectConfigPath.hs         |   5 +-
 .../src/Distribution/Client/CmdBench.hs       |   2 +-
 .../src/Distribution/Client/CmdBuild.hs       |   2 +-
 .../src/Distribution/Client/CmdHaddock.hs     |   2 +-
 .../Distribution/Client/CmdHaddockProject.hs  |   4 +-
 .../src/Distribution/Client/CmdInstall.hs     |   6 +-
 .../src/Distribution/Client/CmdListBin.hs     |   2 +-
 .../src/Distribution/Client/CmdOutdated.hs    | 490 ++++++++++--------
 .../src/Distribution/Client/CmdRepl.hs        |   2 +-
 .../src/Distribution/Client/CmdRun.hs         |   2 +-
 .../src/Distribution/Client/CmdTarget.hs      |   2 +-
 .../src/Distribution/Client/CmdTest.hs        |   2 +-
 cabal-install/src/Distribution/Client/Main.hs |   2 +-
 .../Client/ProjectOrchestration.hs            | 182 ++++++-
 .../Client/ProjectPlanning/Types.hs           |   5 +
 .../src/Distribution/Client/ScriptUtils.hs    |   4 +-
 cabal-install/tests/IntegrationTests2.hs      |   8 +-
 .../PackageTests/Outdated/Issue8283/cabal.out |  44 ++
 .../Outdated/Issue8283/cabal.project          |   4 +
 .../Outdated/Issue8283/cabal.test.hs          |  27 +
 .../Outdated/Issue8283/package-a/LICENSE      |  28 +
 .../Issue8283/package-a/package-a.cabal       |  24 +
 .../Issue8283/package-a/src/ModuleA.hs        |   4 +
 .../Outdated/Issue8283/package-b/LICENSE      |  28 +
 .../Issue8283/package-b/package-b.cabal       |  17 +
 .../Issue8283/package-b/src/ModuleB.hs        |   6 +
 .../Issue8283/repo/base-3.0.3.1/base.cabal    | 154 ++++++
 .../Issue8283/repo/base-3.0.3.2/base.cabal    | 160 ++++++
 .../Issue8283/repo/base-4.0.0.0/base.cabal    | 174 +++++++
 .../repo/binary-0.8.5.0/binary.cabal          |  35 ++
 .../repo/binary-0.8.6.0/binary.cabal          |  35 ++
 .../repo/binary-0.9.0.0/binary.cabal          |  35 ++
 .../Issue8283/repo/preferred-versions         |   1 +
 .../template-haskell.cabal                    |  22 +
 .../template-haskell.cabal                    |  22 +
 .../template-haskell.cabal                    |  32 ++
 .../Outdated/outdated-project-file.out        |  25 +-
 .../Outdated/outdated-project-file.test.hs    |   3 +-
 .../PackageTests/Outdated/outdated.out        |  30 +-
 .../PackageTests/Outdated/outdated_freeze.out |  53 +-
 .../Outdated/outdated_freeze.test.hs          |   2 +-
 cabal.project                                 |   4 +-
 44 files changed, 1400 insertions(+), 297 deletions(-)
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.out
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.project
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.test.hs
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/LICENSE
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/package-a.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/src/ModuleA.hs
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/LICENSE
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/package-b.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/src/ModuleB.hs
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.1/base.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.2/base.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-4.0.0.0/base.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.5.0/binary.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.6.0/binary.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.9.0.0/binary.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/preferred-versions
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.0/template-haskell.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.1/template-haskell.cabal
 create mode 100644 cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.4.0.0/template-haskell.cabal

diff --git a/Cabal-syntax/src/Distribution/Utils/Generic.hs b/Cabal-syntax/src/Distribution/Utils/Generic.hs
index cc609d1264..694f4f6bd4 100644
--- a/Cabal-syntax/src/Distribution/Utils/Generic.hs
+++ b/Cabal-syntax/src/Distribution/Utils/Generic.hs
@@ -56,6 +56,7 @@ module Distribution.Utils.Generic
   , listUnion
   , listUnionRight
   , ordNub
+  , sortNub
   , ordNubBy
   , ordNubRight
   , safeHead
@@ -385,6 +386,10 @@ ordNubRight = fst . foldr go ([], Set.empty)
         then p
         else (x : l, Set.insert x s)
 
+-- | Sort and nub a list
+sortNub :: Ord a => [a] -> [a]
+sortNub = Set.toList . Set.fromList
+
 -- | A right-biased version of 'listUnion'.
 --
 -- Example:
diff --git a/Cabal/src/Distribution/Simple/Utils.hs b/Cabal/src/Distribution/Simple/Utils.hs
index 81763cca8f..d9109ea162 100644
--- a/Cabal/src/Distribution/Simple/Utils.hs
+++ b/Cabal/src/Distribution/Simple/Utils.hs
@@ -185,6 +185,7 @@ module Distribution.Simple.Utils
   , listUnion
   , listUnionRight
   , ordNub
+  , sortNub
   , ordNubBy
   , ordNubRight
   , safeHead
diff --git a/cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs b/cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs
index 17543b5f2d..a6d80dddab 100644
--- a/cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs
+++ b/cabal-install-solver/src/Distribution/Solver/Types/ProjectConfigPath.hs
@@ -38,7 +38,7 @@ import qualified System.FilePath.Posix as Posix
 import qualified System.FilePath.Windows as Windows
 import qualified Data.List.NonEmpty as NE
 import Distribution.Solver.Modular.Version (VR)
-import Distribution.Pretty (prettyShow)
+import Distribution.Pretty (prettyShow, Pretty(..))
 import Distribution.Utils.String (trim)
 import Text.PrettyPrint
 import Distribution.Simple.Utils (ordNub)
@@ -58,6 +58,9 @@ import Distribution.System (OS(Windows), buildOS)
 newtype ProjectConfigPath = ProjectConfigPath (NonEmpty FilePath)
     deriving (Eq, Show, Generic)
 
+instance Pretty ProjectConfigPath where
+  pretty = docProjectConfigPath
+
 -- | Sorts URIs after local file paths and longer file paths after shorter ones
 -- as measured by the number of path segments. If still equal, then sorting is
 -- lexical.
diff --git a/cabal-install/src/Distribution/Client/CmdBench.hs b/cabal-install/src/Distribution/Client/CmdBench.hs
index 0563414128..f6fc6e55d9 100644
--- a/cabal-install/src/Distribution/Client/CmdBench.hs
+++ b/cabal-install/src/Distribution/Client/CmdBench.hs
@@ -132,7 +132,7 @@ benchAction flags@NixStyleFlags{..} targetStrings globalFlags = do
       -- (as opposed to say build or haddock targets).
       targets <-
         either (reportTargetProblems verbosity) return $
-          resolveTargets
+          resolveTargetsFromSolver
             selectPackageTargets
             selectComponentTarget
             elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/CmdBuild.hs b/cabal-install/src/Distribution/Client/CmdBuild.hs
index e668b16532..6c8b654003 100644
--- a/cabal-install/src/Distribution/Client/CmdBuild.hs
+++ b/cabal-install/src/Distribution/Client/CmdBuild.hs
@@ -157,7 +157,7 @@ buildAction flags@NixStyleFlags{extraFlags = buildFlags, ..} targetStrings globa
         -- (as opposed to say repl or haddock targets).
         targets <-
           either (reportBuildTargetProblems verbosity) return $
-            resolveTargets
+            resolveTargetsFromSolver
               selectPackageTargets
               selectComponentTarget
               elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/CmdHaddock.hs b/cabal-install/src/Distribution/Client/CmdHaddock.hs
index 70e9870a07..74f10f44df 100644
--- a/cabal-install/src/Distribution/Client/CmdHaddock.hs
+++ b/cabal-install/src/Distribution/Client/CmdHaddock.hs
@@ -177,7 +177,7 @@ haddockAction relFlags targetStrings globalFlags = do
       -- haddock targets
       targets <-
         either (reportBuildDocumentationTargetProblems verbosity) return $
-          resolveTargets
+          resolveTargetsFromSolver
             (selectPackageTargets haddockFlags)
             selectComponentTarget
             elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs
index b2e59c3340..e69ceff308 100644
--- a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs
+++ b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs
@@ -28,7 +28,7 @@ import Distribution.Client.ProjectOrchestration
   , ProjectBuildContext (..)
   , TargetSelector (..)
   , pruneInstallPlanToTargets
-  , resolveTargets
+  , resolveTargetsFromSolver
   , runProjectPreBuildPhase
   , selectComponentTargetBasic
   )
@@ -146,7 +146,7 @@ haddockProjectAction flags _extraArgs globalFlags = do
           -- (as opposed to say repl or haddock targets).
           targets <-
             either reportTargetProblems return $
-              resolveTargets
+              resolveTargetsFromSolver
                 selectPackageTargets
                 selectComponentTargetBasic
                 elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/CmdInstall.hs b/cabal-install/src/Distribution/Client/CmdInstall.hs
index e08293dff7..a479317069 100644
--- a/cabal-install/src/Distribution/Client/CmdInstall.hs
+++ b/cabal-install/src/Distribution/Client/CmdInstall.hs
@@ -828,7 +828,7 @@ partitionToKnownTargetsAndHackagePackages
   -> IO (TargetsMap, [PackageName])
 partitionToKnownTargetsAndHackagePackages verbosity pkgDb elaboratedPlan targetSelectors = do
   let mTargets =
-        resolveTargets
+        resolveTargetsFromSolver
           selectPackageTargets
           selectComponentTarget
           elaboratedPlan
@@ -868,7 +868,7 @@ partitionToKnownTargetsAndHackagePackages verbosity pkgDb elaboratedPlan targetS
       -- removed (or we've given up).
       targets <-
         either (reportBuildTargetProblems verbosity) return $
-          resolveTargets
+          resolveTargetsFromSolver
             selectPackageTargets
             selectComponentTarget
             elaboratedPlan
@@ -888,7 +888,7 @@ constructProjectBuildContext verbosity baseCtx targetSelectors = do
     -- Interpret the targets on the command line as build targets
     targets <-
       either (reportBuildTargetProblems verbosity) return $
-        resolveTargets
+        resolveTargetsFromSolver
           selectPackageTargets
           selectComponentTarget
           elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/CmdListBin.hs b/cabal-install/src/Distribution/Client/CmdListBin.hs
index df16b98e1a..797db65c39 100644
--- a/cabal-install/src/Distribution/Client/CmdListBin.hs
+++ b/cabal-install/src/Distribution/Client/CmdListBin.hs
@@ -106,7 +106,7 @@ listbinAction flags@NixStyleFlags{..} args globalFlags = do
         -- (as opposed to say repl or haddock targets).
         targets <-
           either (reportTargetProblems verbosity) return $
-            resolveTargets
+            resolveTargetsFromSolver
               selectPackageTargets
               selectComponentTarget
               elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/CmdOutdated.hs b/cabal-install/src/Distribution/Client/CmdOutdated.hs
index f053c862c0..ecd6621283 100644
--- a/cabal-install/src/Distribution/Client/CmdOutdated.hs
+++ b/cabal-install/src/Distribution/Client/CmdOutdated.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE RecordWildCards #-}
 
 -- |
@@ -13,44 +14,22 @@ module Distribution.Client.CmdOutdated
   , outdatedAction
   , ListOutdatedSettings (..)
   , listOutdated
+  , IgnoreMajorVersionBumps (..)
+  , showResult
   )
 where
 
 import Distribution.Client.Compat.Prelude
-import Distribution.Compat.Lens
-  ( _1
-  , _2
-  )
 import Prelude ()
 
+import qualified Data.Set as Set
 import Distribution.Client.Config
   ( SavedConfig
       ( savedConfigureExFlags
-      , savedConfigureFlags
-      , savedGlobalFlags
       )
   )
-import Distribution.Client.DistDirLayout
-  ( DistDirLayout (distProjectFile, distProjectRootDirectory)
-  , defaultDistDirLayout
-  )
-import Distribution.Client.IndexUtils as IndexUtils
+import qualified Distribution.Client.IndexUtils as IndexUtils
 import Distribution.Client.ProjectConfig
-import Distribution.Client.ProjectConfig.Legacy
-  ( instantiateProjectConfigSkeletonWithCompiler
-  )
-import Distribution.Client.ProjectFlags
-  ( ProjectFlags (..)
-  , defaultProjectFlags
-  , projectFlagsOptions
-  , removeIgnoreProjectOption
-  )
-import Distribution.Client.RebuildMonad
-  ( runRebuild
-  )
-import Distribution.Client.Sandbox
-  ( loadConfigOrSandboxConfig
-  )
 import Distribution.Client.Sandbox.PackageEnvironment
   ( loadUserConfig
   )
@@ -60,83 +39,11 @@ import Distribution.Client.Targets
   , userToPackageConstraint
   )
 import Distribution.Client.Types.SourcePackageDb as SourcePackageDb
-import Distribution.Solver.Types.PackageConstraint
-  ( packageConstraintToDependency
-  )
-import Distribution.Utils.Generic
-  ( safeLast
-  , wrapText
-  )
-
-import Distribution.Client.HttpUtils
 import qualified Distribution.Compat.CharParsing as P
-import Distribution.Package
-  ( PackageName
-  , packageVersion
-  )
 import Distribution.PackageDescription
-  ( allBuildDepends
-  )
 import Distribution.PackageDescription.Configuration
-  ( finalizePD
-  )
-import Distribution.ReadE
-  ( parsecToReadE
-  )
-import Distribution.Simple.Command
-  ( CommandUI (..)
-  , OptionField
-  , ShowOrParseArgs
-  , liftOptionL
-  , optArg
-  , option
-  , reqArg
-  )
-import Distribution.Simple.Compiler
-  ( Compiler
-  , compilerInfo
-  )
-import Distribution.Simple.Flag
-  ( Flag
-  , flagToMaybe
-  , fromFlagOrDefault
-  , toFlag
-  )
-import Distribution.Simple.PackageDescription
-  ( readGenericPackageDescription
-  )
-import Distribution.Simple.Setup
-  ( optionVerbosity
-  , trueArg
-  )
-import Distribution.Simple.Utils
-  ( debug
-  , dieWithException
-  , notice
-  , tryFindPackageDesc
-  )
-import Distribution.System
-  ( Platform (..)
-  )
-import Distribution.Types.ComponentRequestedSpec
-  ( ComponentRequestedSpec (..)
-  )
-import Distribution.Types.Dependency
-  ( Dependency (..)
-  )
-import Distribution.Types.DependencySatisfaction
-  ( DependencySatisfaction (..)
-  )
-import Distribution.Types.PackageVersionConstraint
-  ( PackageVersionConstraint (..)
-  , simplifyPackageVersionConstraint
-  )
-import Distribution.Utils.NubList
-  ( fromNubList
-  )
-import Distribution.Verbosity
-  ( normal
-  , silent
+import Distribution.Solver.Types.PackageConstraint
+  ( packageConstraintToDependency
   )
 import Distribution.Version
   ( LowerBound (..)
@@ -149,21 +56,44 @@ import Distribution.Version
   )
 
 import qualified Data.Set as S
-import Distribution.Client.Errors
-import Distribution.Utils.Path (relativeSymbolicPath)
+import Distribution.Client.NixStyleOptions
 import System.Directory
-  ( doesFileExist
-  , getCurrentDirectory
+  ( getCurrentDirectory
   )
 
+import Distribution.Client.ProjectOrchestration
+
+import Control.Monad
+import Distribution.Client.ScriptUtils
+import Distribution.Package
+import Distribution.ReadE
+import Distribution.Simple.Command
+import Distribution.Simple.Flag
+import Distribution.Simple.Setup hiding (GlobalFlags (..))
+import Distribution.Simple.Utils
+import Distribution.Types.PackageVersionConstraint
+import Distribution.Verbosity
+
+import qualified Data.Map.Strict as Map
+import Distribution.Client.CmdErrorMessages
+import Distribution.Client.ProjectPlanning.Types
+import Distribution.Client.TargetProblem
+import Distribution.Client.Types.PackageSpecifier
+import Distribution.Solver.Types.ConstraintSource
+import Distribution.Solver.Types.SourcePackage
+import Distribution.Types.Component
+import qualified Text.PrettyPrint as PP
+
+import Distribution.Client.Errors
+
 -------------------------------------------------------------------------------
 -- Command
 -------------------------------------------------------------------------------
 
-outdatedCommand :: CommandUI (ProjectFlags, OutdatedFlags)
+outdatedCommand :: CommandUI (NixStyleFlags OutdatedFlags)
 outdatedCommand =
   CommandUI
-    { commandName = "outdated"
+    { commandName = "v2-outdated"
     , commandSynopsis = "Check for outdated dependencies."
     , commandDescription = Just $ \_ ->
         wrapText $
@@ -172,12 +102,9 @@ outdatedCommand =
     , commandNotes = Nothing
     , commandUsage = \pname ->
         "Usage: " ++ pname ++ " outdated [FLAGS] [PACKAGES]\n"
-    , commandDefaultFlags = (defaultProjectFlags, defaultOutdatedFlags)
-    , commandOptions = \showOrParseArgs ->
-        map
-          (liftOptionL _1)
-          (removeIgnoreProjectOption (projectFlagsOptions showOrParseArgs))
-          ++ map (liftOptionL _2) (outdatedOptions showOrParseArgs)
+    , commandDefaultFlags = defaultNixStyleFlags defaultOutdatedFlags
+    , commandOptions = nixStyleOptions $ \showOrParseArgs ->
+        outdatedOptions showOrParseArgs
     }
 
 -------------------------------------------------------------------------------
@@ -202,8 +129,7 @@ instance Semigroup IgnoreMajorVersionBumps where
     IgnoreMajorVersionBumpsSome (a ++ b)
 
 data OutdatedFlags = OutdatedFlags
-  { outdatedVerbosity :: Flag Verbosity
-  , outdatedFreezeFile :: Flag Bool
+  { outdatedFreezeFile :: Flag Bool
   , outdatedNewFreezeFile :: Flag Bool
   , outdatedSimpleOutput :: Flag Bool
   , outdatedExitCode :: Flag Bool
@@ -215,8 +141,7 @@ data OutdatedFlags = OutdatedFlags
 defaultOutdatedFlags :: OutdatedFlags
 defaultOutdatedFlags =
   OutdatedFlags
-    { outdatedVerbosity = toFlag normal
-    , outdatedFreezeFile = mempty
+    { outdatedFreezeFile = mempty
     , outdatedNewFreezeFile = mempty
     , outdatedSimpleOutput = mempty
     , outdatedExitCode = mempty
@@ -227,10 +152,7 @@ defaultOutdatedFlags =
 
 outdatedOptions :: ShowOrParseArgs -> [OptionField OutdatedFlags]
 outdatedOptions _showOrParseArgs =
-  [ optionVerbosity
-      outdatedVerbosity
-      (\v flags -> flags{outdatedVerbosity = v})
-  , option
+  [ option
       []
       ["freeze-file", "v1-freeze-file"]
       "Act on the freeze file"
@@ -239,8 +161,8 @@ outdatedOptions _showOrParseArgs =
       trueArg
   , option
       []
-      ["v2-freeze-file", "new-freeze-file"]
-      "Act on the new-style freeze file (default: cabal.project.freeze)"
+      ["project-context", "v2-freeze-file", "new-freeze-file"]
+      "Check for outdated dependencies in the project context, for example, dependencies specified in cabal.project orcabal.project.freeze."
       outdatedNewFreezeFile
       (\v flags -> flags{outdatedNewFreezeFile = v})
       trueArg
@@ -307,54 +229,53 @@ outdatedOptions _showOrParseArgs =
 -- Action
 -------------------------------------------------------------------------------
 
--- | Entry point for the 'outdated' command.
-outdatedAction :: (ProjectFlags, OutdatedFlags) -> [String] -> GlobalFlags -> IO ()
-outdatedAction (ProjectFlags{flagProjectDir, flagProjectFile}, OutdatedFlags{..}) _targetStrings globalFlags = do
-  config <- loadConfigOrSandboxConfig verbosity globalFlags
-  let globalFlags' = savedGlobalFlags config `mappend` globalFlags
-      configFlags = savedConfigureFlags config
-  withRepoContext verbosity globalFlags' $ \repoContext -> do
-    when (not newFreezeFile && (isJust mprojectDir || isJust mprojectFile)) $
-      dieWithException verbosity OutdatedAction
-
-    sourcePkgDb <- IndexUtils.getSourcePackages verbosity repoContext
-    (comp, platform, _progdb) <- configCompilerAux' configFlags
-    deps <-
-      if freezeFile
-        then depsFromFreezeFile verbosity
-        else
-          if newFreezeFile
-            then do
-              httpTransport <-
-                configureTransport
-                  verbosity
-                  (fromNubList . globalProgPathExtra $ globalFlags)
-                  (flagToMaybe . globalHttpTransport $ globalFlags)
-              depsFromNewFreezeFile verbosity httpTransport comp platform mprojectDir mprojectFile
-            else do
-              depsFromPkgDesc verbosity comp platform
-    debug verbosity $
-      "Dependencies loaded: "
-        ++ intercalate ", " (map prettyShow deps)
-    let outdatedDeps =
-          listOutdated
-            deps
-            sourcePkgDb
-            (ListOutdatedSettings ignorePred minorPred)
-    when (not quiet) $
-      showResult verbosity outdatedDeps simpleOutput
-    if exitCode && (not . null $ outdatedDeps)
-      then exitFailure
-      else return ()
+getSourcePackages :: Verbosity -> ProjectConfig -> IO SourcePackageDb
+getSourcePackages verbosity projectConfig =
+  projectConfigWithSolverRepoContext
+    verbosity
+    (projectConfigShared projectConfig)
+    (projectConfigBuildOnly projectConfig)
+    (\ctx -> IndexUtils.getSourcePackages verbosity ctx)
+
+outdatedAction :: NixStyleFlags OutdatedFlags -> [String] -> GlobalFlags -> IO ()
+outdatedAction flags targetStrings globalFlags =
+  withContextAndSelectors
+    AcceptNoTargets
+    Nothing
+    flags
+    targetStrings
+    globalFlags
+    OtherCommand
+    $ \_targetCtx ctx targetSelectors -> do
+      deps <-
+        if
+            | freezeFile -> depsFromFreezeFile verbosity
+            | newFreezeFile -> depsFromProjectContext verbosity (projectConfig ctx)
+            | otherwise -> depsFromLocalPackages verbosity ctx targetSelectors
+
+      debug verbosity $
+        "Dependencies loaded: "
+          ++ intercalate ", " (map prettyShow deps)
+
+      sourcePkgDb <- getSourcePackages verbosity (projectConfig ctx)
+      let outdatedDeps =
+            listOutdated
+              deps
+              sourcePkgDb
+              (ListOutdatedSettings ignorePred minorPred)
+      when (not quiet) $
+        showResult verbosity outdatedDeps simpleOutput
+      if exitCode && (not . null $ outdatedDeps)
+        then exitFailure
+        else return ()
   where
+    OutdatedFlags{..} = extraFlags flags
     verbosity =
       if quiet
         then silent
-        else fromFlagOrDefault normal outdatedVerbosity
+        else fromFlagOrDefault normal (setupVerbosity (configCommonFlags (configFlags flags)))
     freezeFile = fromFlagOrDefault False outdatedFreezeFile
     newFreezeFile = fromFlagOrDefault False outdatedNewFreezeFile
-    mprojectDir = flagToMaybe flagProjectDir
-    mprojectFile = flagToMaybe flagProjectFile
     simpleOutput = fromFlagOrDefault False outdatedSimpleOutput
     quiet = fromFlagOrDefault False outdatedQuiet
     exitCode = fromFlagOrDefault quiet outdatedExitCode
@@ -369,93 +290,153 @@ outdatedAction (ProjectFlags{flagProjectDir, flagProjectFile}, OutdatedFlags{..}
         let minorSet = S.fromList pkgs
          in \pkgname -> pkgname `S.member` minorSet
 
+reportOutdatedTargetProblem :: Verbosity -> [TargetProblem'] -> IO a
+reportOutdatedTargetProblem verbosity problems =
+  reportTargetProblems verbosity "check outdated dependencies for" problems
+
 -- | Print either the list of all outdated dependencies, or a message
 -- that there are none.
-showResult :: Verbosity -> [(PackageVersionConstraint, Version)] -> Bool -> IO ()
+showResult :: Verbosity -> [OutdatedDependency] -> Bool -> IO ()
 showResult verbosity outdatedDeps simpleOutput =
   if not . null $ outdatedDeps
     then do
       when (not simpleOutput) $
         notice verbosity "Outdated dependencies:"
-      for_ outdatedDeps $ \(d@(PackageVersionConstraint pn _), v) ->
-        let outdatedDep =
-              if simpleOutput
-                then prettyShow pn
-                else prettyShow d ++ " (latest: " ++ prettyShow v ++ ")"
-         in notice verbosity outdatedDep
+      if simpleOutput
+        then -- Simple output just prints package names, one per line
+          outputSimple
+        else -- Hierarchical output grouped by package and component
+          outputStructured
     else notice verbosity "All dependencies are up to date."
+  where
+    -- Group dependencies by package and component
+    groupByPackage :: [OutdatedDependency] -> [(String, [(String, [OutdatedDependency])])]
+    groupByPackage deps =
+      let
+        -- First, create a list of (package, component, dependency) tuples
+        pkgCompDeps =
+          [ (extractPackageName src, extractComponentName src, dep)
+          | dep@(OutdatedDependency _ _ src) <- deps
+          ]
+        -- Group by package
+        pkgGroups =
+          Map.fromListWith
+            (Map.unionWith (++))
+            [ (pkg, (Map.singleton comp [d]))
+            | (pkg, comp, d) <- pkgCompDeps
+            ]
+       in
+        Map.toList (Map.map Map.toList pkgGroups)
+
+    -- Extract package name from the source
+    extractPackageName :: OutdatedDependencySource -> String
+    extractPackageName (ConfigSource _) = "project-config"
+    extractPackageName (ComponentSource pkgId _) = prettyShow (pkgName pkgId)
+
+    -- Extract component name from the source
+    extractComponentName :: OutdatedDependencySource -> String
+    extractComponentName (ConfigSource src) = showConstraintSource src
+    extractComponentName (ComponentSource pkgId ctarget) = showComponentTarget pkgId ctarget
+
+    getConstraintPackageName :: PackageVersionConstraint -> PackageName
+    getConstraintPackageName (PackageVersionConstraint pn _) = pn
+
+    outputSimple =
+      let pns = sortNub $ map (getConstraintPackageName . outdatedDependency) outdatedDeps
+       in for_ pns $ \pn ->
+            noticeNoWrap verbosity (prettyShow pn)
+
+    outputStructured =
+      let
+        -- Group by package name, then by component
+        packageGroups = groupByPackage outdatedDeps
+       in
+        for_ packageGroups $ \(pkgName, componentGroups) -> do
+          noticeNoWrap verbosity $ "* " ++ pkgName
+          for_ componentGroups $ \(compName, deps) -> do
+            noticeNoWrap verbosity $ "  - " ++ compName
+            for_ (sortBy (comparing (getConstraintPackageName . outdatedDependency)) deps) $
+              \(OutdatedDependency d v _) ->
+                noticeNoWrap verbosity $ "    * " ++ prettyShow d ++ " (latest: " ++ prettyShow v ++ ")"
+
+data OutdatedDependencyX v = OutdatedDependency
+  { outdatedDependency :: PackageVersionConstraint
+  , _outdatedVersion :: v
+  , _outdatedSource :: OutdatedDependencySource
+  }
+
+instance Pretty (OutdatedDependencyX Version) where
+  pretty (OutdatedDependency dep ver src) =
+    pretty dep
+      <+> PP.text "(latest:"
+      <+> pretty ver
+      <+> PP.text ","
+      <+> PP.text "from:"
+      <+> PP.text (prettyOutdatedDependencySource src)
+      <+> PP.text ")"
+
+instance Pretty (OutdatedDependencyX ()) where
+  pretty (OutdatedDependency dep _ src) =
+    pretty dep <+> PP.text "(from:" <+> PP.text (prettyOutdatedDependencySource src) `mappend` PP.text ")"
+
+data OutdatedDependencySource = ConfigSource ConstraintSource | ComponentSource PackageId ComponentTarget
+
+-- | Pretty print an 'OutdatedDependencySource'.
+prettyOutdatedDependencySource :: OutdatedDependencySource -> String
+prettyOutdatedDependencySource (ConfigSource src) = showConstraintSource src
+prettyOutdatedDependencySource (ComponentSource pkgId ctarget) = prettyShow pkgId ++ ":" ++ showComponentTarget pkgId ctarget
+
+type CandidateOutdatedDependency = OutdatedDependencyX ()
+
+mkCandidateOutdatedDependency :: PackageVersionConstraint -> OutdatedDependencySource -> CandidateOutdatedDependency
+mkCandidateOutdatedDependency dep src = OutdatedDependency dep () src
+
+type OutdatedDependency = OutdatedDependencyX Version
 
 -- | Convert a list of 'UserConstraint's to a 'Dependency' list.
-userConstraintsToDependencies :: [UserConstraint] -> [PackageVersionConstraint]
+userConstraintsToDependencies :: [(UserConstraint, ConstraintSource)] -> [CandidateOutdatedDependency]
 userConstraintsToDependencies ucnstrs =
-  mapMaybe (packageConstraintToDependency . userToPackageConstraint) ucnstrs
+  mapMaybe (\(uc, src) -> fmap (flip mkCandidateOutdatedDependency (ConfigSource src)) (packageConstraintToDependency . userToPackageConstraint $ uc)) ucnstrs
 
 -- | Read the list of dependencies from the freeze file.
-depsFromFreezeFile :: Verbosity -> IO [PackageVersionConstraint]
+depsFromFreezeFile :: Verbosity -> IO [CandidateOutdatedDependency]
 depsFromFreezeFile verbosity = do
   cwd <- getCurrentDirectory
   userConfig <- loadUserConfig verbosity cwd Nothing
   let ucnstrs =
-        map fst . configExConstraints . savedConfigureExFlags $
+        configExConstraints . savedConfigureExFlags $
           userConfig
       deps = userConstraintsToDependencies ucnstrs
   debug verbosity "Reading the list of dependencies from the freeze file"
   return deps
 
--- | Read the list of dependencies from the new-style freeze file.
-depsFromNewFreezeFile :: Verbosity -> HttpTransport -> Compiler -> Platform -> Maybe FilePath -> Maybe FilePath -> IO [PackageVersionConstraint]
-depsFromNewFreezeFile verbosity httpTransport compiler (Platform arch os) mprojectDir mprojectFile = do
-  projectRoot <-
-    either throwIO return
-      =<< findProjectRoot verbosity mprojectDir mprojectFile
-  let distDirLayout =
-        defaultDistDirLayout
-          projectRoot
-          {- TODO: Support dist dir override -} Nothing
-          Nothing
-  projectConfig <- runRebuild (distProjectRootDirectory distDirLayout) $ do
-    pcs <- readProjectLocalFreezeConfig verbosity httpTransport distDirLayout
-    pure $ instantiateProjectConfigSkeletonWithCompiler os arch (compilerInfo compiler) mempty pcs
-  let ucnstrs =
-        map fst . projectConfigConstraints . projectConfigShared $
-          projectConfig
+-- | Read the list of dependencies from the cabal.project context.
+-- This will get dependencies from
+--  * cabal.project.freeze
+--  * cabal.project.local
+--  * cabal.project
+-- files
+depsFromProjectContext :: Verbosity -> ProjectConfig -> IO [CandidateOutdatedDependency]
+depsFromProjectContext verbosity projectConfig = do
+  let ucnstrs = projectConfigConstraints $ projectConfigShared projectConfig
       deps = userConstraintsToDependencies ucnstrs
-      freezeFile = distProjectFile distDirLayout "freeze"
-  freezeFileExists <- doesFileExist freezeFile
-
-  unless freezeFileExists $
-    dieWithException verbosity $
-      FreezeFileExistsErr freezeFile
-
+      provenance = projectConfigProvenance projectConfig
   debug verbosity $
-    "Reading the list of dependencies from the new-style freeze file " ++ freezeFile
+    "Reading the list of dependencies from the project files: "
+      ++ intercalate ", " [prettyShow p | Explicit p <- Set.toList provenance]
   return deps
 
 -- | Read the list of dependencies from the package description.
-depsFromPkgDesc :: Verbosity -> Compiler -> Platform -> IO [PackageVersionConstraint]
-depsFromPkgDesc verbosity comp platform = do
-  path <- tryFindPackageDesc verbosity Nothing
-  gpd <- readGenericPackageDescription verbosity Nothing (relativeSymbolicPath path)
-  let cinfo = compilerInfo comp
-      epd =
-        finalizePD
-          mempty
-          (ComponentRequestedSpec True True)
-          (const Satisfied)
-          platform
-          cinfo
-          []
-          gpd
-  case epd of
-    Left _ -> dieWithException verbosity FinalizePDFailed
-    Right (pd, _) -> do
-      let bd = allBuildDepends pd
-      debug
-        verbosity
-        "Reading the list of dependencies from the package description"
-      return $ map toPVC bd
+depsFromPkgDesc :: Verbosity -> PackageId -> GenericPackageDescription -> ComponentTarget -> IO [CandidateOutdatedDependency]
+depsFromPkgDesc verbosity pkgId gpd t@(ComponentTarget cname _subtarget) = do
+  let pd = flattenPackageDescription gpd
+      bd = targetBuildDepends (componentBuildInfo (getComponent pd cname))
+  debug
+    verbosity
+    "Reading the list of dependencies from the package description"
+  return $ map toPVC bd
   where
-    toPVC (Dependency pn vr _) = PackageVersionConstraint pn vr
+    toPVC (Dependency pn vr _) = mkCandidateOutdatedDependency (PackageVersionConstraint pn vr) (ComponentSource pkgId t)
 
 -- | Various knobs for customising the behaviour of 'listOutdated'.
 data ListOutdatedSettings = ListOutdatedSettings
@@ -467,20 +448,22 @@ data ListOutdatedSettings = ListOutdatedSettings
 
 -- | Find all outdated dependencies.
 listOutdated
-  :: [PackageVersionConstraint]
+  :: [CandidateOutdatedDependency]
   -> SourcePackageDb
   -> ListOutdatedSettings
-  -> [(PackageVersionConstraint, Version)]
+  -> [OutdatedDependency]
 listOutdated deps sourceDb (ListOutdatedSettings ignorePred minorPred) =
-  mapMaybe isOutdated $ map simplifyPackageVersionConstraint deps
+  mapMaybe isOutdated deps
   where
-    isOutdated :: PackageVersionConstraint -> Maybe (PackageVersionConstraint, Version)
-    isOutdated dep@(PackageVersionConstraint pname vr)
+    isOutdated :: CandidateOutdatedDependency -> Maybe OutdatedDependency
+    isOutdated (OutdatedDependency dep () src)
       | ignorePred pname = Nothing
       | otherwise =
           let this = map packageVersion $ SourcePackageDb.lookupDependency sourceDb pname vr
               latest = lookupLatest dep
-           in (\v -> (dep, v)) `fmap` isOutdated' this latest
+           in (\v -> OutdatedDependency dep v src) `fmap` isOutdated' this latest
+      where
+        PackageVersionConstraint pname vr = simplifyPackageVersionConstraint dep
 
     isOutdated' :: [Version] -> [Version] -> Maybe Version
     isOutdated' [] _ = Nothing
@@ -506,3 +489,50 @@ listOutdated deps sourceDb (ListOutdatedSettings ignorePred minorPred) =
           case upper of
             NoUpperBound -> vr
             UpperBound _v1 _ -> majorBoundVersion v0
+
+-- | For the outdated command, when a whole package is specified we want
+-- to select all buildable components.
+selectPackageTargetsForOutdated
+  :: TargetSelector
+  -> [AvailableTarget k]
+  -> Either (TargetProblem') [k]
+selectPackageTargetsForOutdated targetSelector targets
+  -- No targets available at all is an error
+  | null targets = Left (TargetProblemNoTargets targetSelector)
+  -- We select all buildable components for a package
+  | otherwise = Right $ selectBuildableTargets targets
+
+-- | For the outdated command, when a specific component is specified
+-- we simply select that component.
+selectComponentTargetForOutdated
+  :: SubComponentTarget
+  -> AvailableTarget k
+  -> Either (TargetProblem') k
+selectComponentTargetForOutdated subtarget target =
+  selectComponentTargetBasic subtarget target
+
+-- | Read the list of dependencies from local packages
+depsFromLocalPackages :: Verbosity -> ProjectBaseContext -> [TargetSelector] -> IO [CandidateOutdatedDependency]
+depsFromLocalPackages verbosity ctx targetSelectors = do
+  when (null targetSelectors) $
+    dieWithException verbosity TargetSelectorNoTargetsInCwdTrue
+  targets <-
+    either (reportOutdatedTargetProblem verbosity) return $
+      resolveTargetsFromLocalPackages
+        selectPackageTargetsForOutdated
+        selectComponentTargetForOutdated
+        (localPackages ctx)
+        targetSelectors
+  fmap concat <$> forM (localPackages ctx) $ \pkg -> case pkg of
+    SpecificSourcePackage pkg' -> do
+      -- Find the package in the resolved targets
+      let pkgId = packageId pkg'
+      let pkgTargets =
+            case Map.lookup pkgId targets of
+              Just componentTargets -> map fst componentTargets
+              Nothing -> []
+      -- If no specific components were targeted, use the whole package
+      -- Get dependencies for each targeted component
+      fmap concat <$> forM pkgTargets $ \target ->
+        depsFromPkgDesc verbosity pkgId (srcpkgDescription pkg') target
+    _ -> return []
diff --git a/cabal-install/src/Distribution/Client/CmdRepl.hs b/cabal-install/src/Distribution/Client/CmdRepl.hs
index ad02342e2a..6eef1221e4 100644
--- a/cabal-install/src/Distribution/Client/CmdRepl.hs
+++ b/cabal-install/src/Distribution/Client/CmdRepl.hs
@@ -516,7 +516,7 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g
       -- (as opposed to say build or haddock targets).
       targets <-
         either (reportTargetProblems verbosity) return $
-          resolveTargets
+          resolveTargetsFromSolver
             (selectPackageTargets multi_repl_enabled)
             selectComponentTarget
             elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/CmdRun.hs b/cabal-install/src/Distribution/Client/CmdRun.hs
index 0000a2927a..e96054fb57 100644
--- a/cabal-install/src/Distribution/Client/CmdRun.hs
+++ b/cabal-install/src/Distribution/Client/CmdRun.hs
@@ -228,7 +228,7 @@ runAction flags@NixStyleFlags{..} targetAndArgs globalFlags =
         -- (as opposed to say repl or haddock targets).
         targets <-
           either (reportTargetProblems verbosity) return $
-            resolveTargets
+            resolveTargetsFromSolver
               selectPackageTargets
               selectComponentTarget
               elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/CmdTarget.hs b/cabal-install/src/Distribution/Client/CmdTarget.hs
index c2edeeec89..6fc0f9f973 100644
--- a/cabal-install/src/Distribution/Client/CmdTarget.hs
+++ b/cabal-install/src/Distribution/Client/CmdTarget.hs
@@ -172,7 +172,7 @@ targetAction flags@NixStyleFlags{..} ts globalFlags = do
 
   targets :: TargetsMap <-
     either (reportBuildTargetProblems verbosity) return $
-      resolveTargets
+      resolveTargetsFromSolver
         selectPackageTargets
         selectComponentTarget
         elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/CmdTest.hs b/cabal-install/src/Distribution/Client/CmdTest.hs
index c839a00c44..272d5b5874 100644
--- a/cabal-install/src/Distribution/Client/CmdTest.hs
+++ b/cabal-install/src/Distribution/Client/CmdTest.hs
@@ -146,7 +146,7 @@ testAction flags@NixStyleFlags{..} targetStrings globalFlags = do
       -- (as opposed to say build or haddock targets).
       targets <-
         either (reportTargetProblems verbosity failWhenNoTestSuites) return $
-          resolveTargets
+          resolveTargetsFromSolver
             selectPackageTargets
             selectComponentTarget
             elaboratedPlan
diff --git a/cabal-install/src/Distribution/Client/Main.hs b/cabal-install/src/Distribution/Client/Main.hs
index 1a8d945611..116c682008 100644
--- a/cabal-install/src/Distribution/Client/Main.hs
+++ b/cabal-install/src/Distribution/Client/Main.hs
@@ -440,7 +440,6 @@ mainWorker args = do
       , regularCmd userConfigCommand userConfigAction
       , regularCmd CmdPath.pathCommand CmdPath.pathAction
       , regularCmd genBoundsCommand genBoundsAction
-      , regularCmd CmdOutdated.outdatedCommand CmdOutdated.outdatedAction
       , wrapperCmd hscolourCommand hscolourCommonFlags
       , hiddenCmd formatCommand formatAction
       , hiddenCmd actAsSetupCommand actAsSetupAction
@@ -465,6 +464,7 @@ mainWorker args = do
           , newCmd CmdClean.cleanCommand CmdClean.cleanAction
           , newCmd CmdSdist.sdistCommand CmdSdist.sdistAction
           , newCmd CmdTarget.targetCommand CmdTarget.targetAction
+          , newCmd CmdOutdated.outdatedCommand CmdOutdated.outdatedAction
           , legacyCmd configureExCommand configureAction
           , legacyCmd buildCommand buildAction
           , legacyCmd replCommand replAction
diff --git a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs
index a14d43e4b9..9b12f57025 100644
--- a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs
+++ b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs
@@ -58,7 +58,8 @@ module Distribution.Client.ProjectOrchestration
     -- ** Selecting what targets we mean
   , readTargetSelectors
   , reportTargetSelectorProblems
-  , resolveTargets
+  , resolveTargetsFromSolver
+  , resolveTargetsFromLocalPackages
   , TargetsMap
   , allTargetSelectors
   , uniqueTargetSelectors
@@ -146,6 +147,7 @@ import Distribution.Client.Types
 import Distribution.Solver.Types.PackageIndex
   ( lookupPackageName
   )
+import Distribution.Solver.Types.SourcePackage (SourcePackage (..))
 
 import Distribution.Client.BuildReports.Anonymous (cabalInstallID)
 import qualified Distribution.Client.BuildReports.Anonymous as BuildReports
@@ -169,7 +171,9 @@ import Distribution.Types.UnqualComponentName
   , packageNameToUnqualComponentName
   )
 
+import Distribution.PackageDescription.Configuration
 import Distribution.Solver.Types.OptionalStanza
+import Distribution.Types.Component
 
 import Control.Exception (assert)
 import qualified Data.List.NonEmpty as NE
@@ -564,7 +568,9 @@ runProjectPostBuildPhase
 -- matched this target. Typically this is exactly one, but in general it is
 -- possible to for different selectors to match the same target. This extra
 -- information is primarily to help make helpful error messages.
-type TargetsMap = Map UnitId [(ComponentTarget, NonEmpty TargetSelector)]
+type TargetsMap = TargetsMapX UnitId
+
+type TargetsMapX u = Map u [(ComponentTarget, NonEmpty TargetSelector)]
 
 -- | Get all target selectors.
 allTargetSelectors :: TargetsMap -> [TargetSelector]
@@ -574,6 +580,63 @@ allTargetSelectors = concatMap (NE.toList . snd) . concat . Map.elems
 uniqueTargetSelectors :: TargetsMap -> [TargetSelector]
 uniqueTargetSelectors = ordNub . allTargetSelectors
 
+-- | Resolve targets from a solver result.
+--
+-- This is a convenience wrapper around 'resolveTargetsFromSolver' that takes an
+-- 'ElaboratedInstallPlan' directly, rather than requiring the caller to
+-- construct the 'AvailableTargetIndexes' first.
+resolveTargetsFromSolver
+  :: forall err
+   . ( forall k
+        . TargetSelector
+       -> [AvailableTarget k]
+       -> Either (TargetProblem err) [k]
+     )
+  -> ( forall k
+        . SubComponentTarget
+       -> AvailableTarget k
+       -> Either (TargetProblem err) k
+     )
+  -> ElaboratedInstallPlan
+  -> Maybe (SourcePackageDb)
+  -> [TargetSelector]
+  -> Either [TargetProblem err] TargetsMap
+resolveTargetsFromSolver selectPackageTargets selectComponentTarget installPlan sourceDb targetSelectors =
+  resolveTargets
+    selectPackageTargets
+    selectComponentTarget
+    (availableTargetIndexes installPlan)
+    sourceDb
+    targetSelectors
+
+-- | Resolve targets from local packages.
+--
+-- This is a convenience wrapper around 'resolveTargets' that takes a list of
+-- 'PackageSpecifier's directly, rather than requiring the caller to
+-- construct the 'AvailableTargetIndexes' first.
+resolveTargetsFromLocalPackages
+  :: forall err
+   . ( forall k
+        . TargetSelector
+       -> [AvailableTarget k]
+       -> Either (TargetProblem err) [k]
+     )
+  -> ( forall k
+        . SubComponentTarget
+       -> AvailableTarget k
+       -> Either (TargetProblem err) k
+     )
+  -> [PackageSpecifier UnresolvedSourcePackage]
+  -> [TargetSelector]
+  -> Either [TargetProblem err] (TargetsMapX PackageId)
+resolveTargetsFromLocalPackages selectPackageTargets selectComponentTarget pkgSpecifiers targetSelectors =
+  resolveTargets
+    selectPackageTargets
+    selectComponentTarget
+    (availableTargetIndexesFromSourcePackages pkgSpecifiers)
+    Nothing
+    targetSelectors
+
 -- | Given a set of 'TargetSelector's, resolve which 'UnitId's and
 -- 'ComponentTarget's they ought to refer to.
 --
@@ -606,8 +669,9 @@ uniqueTargetSelectors = ordNub . allTargetSelectors
 -- this commands can use 'selectComponentTargetBasic', either directly or as
 -- a basis for their own @selectComponentTarget@ implementation.
 resolveTargets
-  :: forall err
-   . ( forall k
+  :: forall u err
+   . Ord u
+  => ( forall k
         . TargetSelector
        -> [AvailableTarget k]
        -> Either (TargetProblem err) [k]
@@ -617,14 +681,14 @@ resolveTargets
        -> AvailableTarget k
        -> Either (TargetProblem err) k
      )
-  -> ElaboratedInstallPlan
+  -> AvailableTargetIndexes u
   -> Maybe (SourcePackageDb)
   -> [TargetSelector]
-  -> Either [TargetProblem err] TargetsMap
+  -> Either [TargetProblem err] (TargetsMapX u)
 resolveTargets
   selectPackageTargets
   selectComponentTarget
-  installPlan
+  AvailableTargetIndexes{..}
   mPkgDb =
     fmap mkTargetsMap
       . either (Left . toList) Right
@@ -632,8 +696,8 @@ resolveTargets
       . map (\ts -> (,) ts <$> checkTarget ts)
     where
       mkTargetsMap
-        :: [(TargetSelector, [(UnitId, ComponentTarget)])]
-        -> TargetsMap
+        :: [(TargetSelector, [(u, ComponentTarget)])]
+        -> TargetsMapX u
       mkTargetsMap targets =
         Map.map nubComponentTargets $
           Map.fromListWith
@@ -643,9 +707,7 @@ resolveTargets
             , (uid, ct) <- cts
             ]
 
-      AvailableTargetIndexes{..} = availableTargetIndexes installPlan
-
-      checkTarget :: TargetSelector -> Either (TargetProblem err) [(UnitId, ComponentTarget)]
+      checkTarget :: TargetSelector -> Either (TargetProblem err) [(u, ComponentTarget)]
 
       -- We can ask to build any whole package, project-local or a dependency
       checkTarget bt@(TargetPackage _ (ordNub -> [pkgid]) mkfilter)
@@ -737,19 +799,19 @@ resolveTargets
         (\(es, xs) -> case es of [] -> Right xs; (e : es') -> Left (e :| es'))
           . partitionEithers
 
-data AvailableTargetIndexes = AvailableTargetIndexes
+data AvailableTargetIndexes u = AvailableTargetIndexes
   { availableTargetsByPackageIdAndComponentName
-      :: AvailableTargetsMap (PackageId, ComponentName)
+      :: AvailableTargetsMap (PackageId, ComponentName) u
   , availableTargetsByPackageId
-      :: AvailableTargetsMap PackageId
+      :: AvailableTargetsMap PackageId u
   , availableTargetsByPackageName
-      :: AvailableTargetsMap PackageName
+      :: AvailableTargetsMap PackageName u
   , availableTargetsByPackageNameAndComponentName
-      :: AvailableTargetsMap (PackageName, ComponentName)
+      :: AvailableTargetsMap (PackageName, ComponentName) u
   , availableTargetsByPackageNameAndUnqualComponentName
-      :: AvailableTargetsMap (PackageName, UnqualComponentName)
+      :: AvailableTargetsMap (PackageName, UnqualComponentName) u
   }
-type AvailableTargetsMap k = Map k [AvailableTarget (UnitId, ComponentName)]
+type AvailableTargetsMap k u = Map k [AvailableTarget (u, ComponentName)]
 
 -- We define a bunch of indexes to help 'resolveTargets' with resolving
 -- 'TargetSelector's to specific 'UnitId's.
@@ -760,7 +822,7 @@ type AvailableTargetsMap k = Map k [AvailableTarget (UnitId, ComponentName)]
 --
 -- They are all constructed lazily because they are not necessarily all used.
 --
-availableTargetIndexes :: ElaboratedInstallPlan -> AvailableTargetIndexes
+availableTargetIndexes :: ElaboratedInstallPlan -> AvailableTargetIndexes UnitId
 availableTargetIndexes installPlan = AvailableTargetIndexes{..}
   where
     availableTargetsByPackageIdAndComponentName
@@ -833,6 +895,86 @@ availableTargetIndexes installPlan = AvailableTargetIndexes{..}
             ElabPackage _ -> null (pkgComponents (elabPkgDescription pkg))
         ]
 
+-- | Create available target indexes from source packages.
+--
+-- This is useful when we need to resolve targets before solver resolution.
+availableTargetIndexesFromSourcePackages
+  :: [PackageSpecifier UnresolvedSourcePackage] -> AvailableTargetIndexes PackageId
+availableTargetIndexesFromSourcePackages pkgSpecifiers = AvailableTargetIndexes{..}
+  where
+    -- Create a map of available targets from source packages
+    availableTargetsByPackageIdAndComponentName
+      :: Map (PackageId, ComponentName) [AvailableTarget (PackageId, ComponentName)]
+    availableTargetsByPackageIdAndComponentName =
+      Map.fromListWith (++) $
+        concat
+          [ [ ((pkgId, cname), [makeAvailableTarget pkgId cname])
+            | let pkgId = packageId pkg
+            , cname <- map componentName (pkgComponents $ flattenPackageDescription (srcpkgDescription pkg))
+            ]
+          | SpecificSourcePackage pkg <- pkgSpecifiers
+          ]
+
+    -- Helper to create an available target
+    makeAvailableTarget pkgId cname =
+      AvailableTarget
+        { availableTargetPackageId = pkgId
+        , availableTargetComponentName = cname
+        , availableTargetStatus = TargetBuildable (pkgId, cname) TargetRequestedByDefault
+        , availableTargetLocalToProject = True
+        }
+
+    -- Derive other indexes from the main one, just like in availableTargetIndexes
+    availableTargetsByPackageId
+      :: Map PackageId [AvailableTarget (PackageId, ComponentName)]
+    availableTargetsByPackageId =
+      Map.mapKeysWith
+        (++)
+        (\(pkgid, _cname) -> pkgid)
+        availableTargetsByPackageIdAndComponentName
+        `Map.union` availableTargetsEmptyPackages
+
+    -- Handle empty packages
+    availableTargetsEmptyPackages =
+      Map.fromList
+        [ (packageId pkg, [])
+        | SpecificSourcePackage pkg <- pkgSpecifiers
+        , null (pkgComponents (flattenPackageDescription (srcpkgDescription pkg)))
+        ]
+
+    availableTargetsByPackageName
+      :: Map PackageName [AvailableTarget (PackageId, ComponentName)]
+    availableTargetsByPackageName =
+      Map.mapKeysWith
+        (++)
+        packageName
+        availableTargetsByPackageId
+
+    availableTargetsByPackageNameAndComponentName
+      :: Map (PackageName, ComponentName) [AvailableTarget (PackageId, ComponentName)]
+    availableTargetsByPackageNameAndComponentName =
+      Map.mapKeysWith
+        (++)
+        (\(pkgid, cname) -> (packageName pkgid, cname))
+        availableTargetsByPackageIdAndComponentName
+
+    availableTargetsByPackageNameAndUnqualComponentName
+      :: Map (PackageName, UnqualComponentName) [AvailableTarget (PackageId, ComponentName)]
+    availableTargetsByPackageNameAndUnqualComponentName =
+      Map.mapKeysWith
+        (++)
+        ( \(pkgid, cname) ->
+            let pname = packageName pkgid
+                cname' = unqualComponentName pname cname
+             in (pname, cname')
+        )
+        availableTargetsByPackageIdAndComponentName
+      where
+        unqualComponentName :: PackageName -> ComponentName -> UnqualComponentName
+        unqualComponentName pkgname =
+          fromMaybe (packageNameToUnqualComponentName pkgname)
+            . componentNameString
+
 -- TODO: [research required] what if the solution has multiple
 --      versions of this package?
 --      e.g. due to setup deps or due to multiple independent sets
diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs
index 7ee5cb52f4..05aefecc77 100644
--- a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs
+++ b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs
@@ -57,6 +57,7 @@ module Distribution.Client.ProjectPlanning.Types
   , isTestComponentTarget
   , isBenchComponentTarget
   , componentOptionalStanza
+  , componentTargetName
 
     -- * Setup script
   , SetupScriptStyle (..)
@@ -861,6 +862,10 @@ data ComponentTarget = ComponentTarget ComponentName SubComponentTarget
 instance Binary ComponentTarget
 instance Structured ComponentTarget
 
+-- | Extract the component name from a 'ComponentTarget'.
+componentTargetName :: ComponentTarget -> ComponentName
+componentTargetName (ComponentTarget cname _) = cname
+
 -- | Unambiguously render a 'ComponentTarget', e.g., to pass
 -- to a Cabal Setup script.
 showComponentTarget :: PackageId -> ComponentTarget -> String
diff --git a/cabal-install/src/Distribution/Client/ScriptUtils.hs b/cabal-install/src/Distribution/Client/ScriptUtils.hs
index 5068323e87..064eec53ad 100644
--- a/cabal-install/src/Distribution/Client/ScriptUtils.hs
+++ b/cabal-install/src/Distribution/Client/ScriptUtils.hs
@@ -318,13 +318,13 @@ withContextAndSelectors noTargets kind flags@NixStyleFlags{..} targetStrings glo
           Left (TargetSelectorNoTargetsInCwd{} : _)
             | [] <- targetStrings
             , AcceptNoTargets <- noTargets ->
-                return (tc, ctx, defaultTarget)
+                return (tc, ctx, [])
           Left err@(TargetSelectorNoTargetsInProject : _)
             -- If there are no target selectors and no targets are fine, return
             -- the context
             | [] <- targetStrings
             , AcceptNoTargets <- noTargets ->
-                return (tc, ctx, defaultTarget)
+                return (tc, ctx, [])
             | (script : _) <- targetStrings -> scriptOrError script err
           Left err@(TargetSelectorNoSuch t _ : _)
             | TargetString1 script <- t -> scriptOrError script err
diff --git a/cabal-install/tests/IntegrationTests2.hs b/cabal-install/tests/IntegrationTests2.hs
index 3cbb9d15b6..69c4134f14 100644
--- a/cabal-install/tests/IntegrationTests2.hs
+++ b/cabal-install/tests/IntegrationTests2.hs
@@ -18,7 +18,7 @@ import Distribution.Client.ProjectBuilding
 import Distribution.Client.ProjectConfig
 import Distribution.Client.ProjectOrchestration
   ( distinctTargetComponents
-  , resolveTargets
+  , resolveTargetsFromSolver
   )
 import Distribution.Client.ProjectPlanning
 import Distribution.Client.ProjectPlanning.Types
@@ -1778,7 +1778,7 @@ assertProjectDistinctTargets
             ++ show results
     where
       results =
-        resolveTargets
+        resolveTargetsFromSolver
           selectPackageTargets
           selectComponentTarget
           elaboratedPlan
@@ -1828,7 +1828,7 @@ assertTargetProblems elaboratedPlan selectPackageTargets selectComponentTarget =
   where
     assertTargetProblem expected targetSelector =
       let res =
-            resolveTargets
+            resolveTargetsFromSolver
               selectPackageTargets
               selectComponentTarget
               elaboratedPlan
@@ -1839,7 +1839,7 @@ assertTargetProblems elaboratedPlan selectPackageTargets selectComponentTarget =
               problem @?= expected targetSelector
             unexpected ->
               assertFailure $
-                "expected resolveTargets result: (Left [problem]) "
+                "expected resolveTargetsFromSolver result: (Left [problem]) "
                   ++ "but got: "
                   ++ show unexpected
 
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.out b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.out
new file mode 100644
index 0000000000..08d8c0ec51
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.out
@@ -0,0 +1,44 @@
+# cabal v2-update
+Downloading the latest package list from test-local-repo
+# cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+Outdated dependencies:
+* package-a
+  - lib:package-a
+    * template-haskell >=2.3 && <2.4 (latest: 2.4.0.0)
+    * template-haskell >=2.3.0 && <2.3.1 (latest: 2.4.0.0)
+* package-b
+  - lib:package-b
+    * base >=3.0 && <3.5 (latest: 4.0.0.0)
+# cabal v2-outdated
+Configuration is affected by the following files:
+- cabal.project
+Outdated dependencies:
+* package-a
+  - lib:package-a
+    * template-haskell >=2.3 && <2.4 (latest: 2.4.0.0)
+    * template-haskell >=2.3.0 && <2.3.1 (latest: 2.4.0.0)
+# cabal v2-outdated
+Configuration is affected by the following files:
+- cabal.project
+base
+template-haskell
+# cabal v2-outdated
+Configuration is affected by the following files:
+- cabal.project
+Outdated dependencies:
+* project-config
+  - project config cabal.project
+    * base ==3.0.3.2 (latest: 4.0.0.0)
+# cabal v2-outdated
+Configuration is affected by the following files:
+- cabal.project
+Outdated dependencies:
+* package-a
+  - lib:package-a
+    * template-haskell >=2.3 && <2.4 (latest: 2.4.0.0)
+    * template-haskell >=2.3.0 && <2.3.1 (latest: 2.4.0.0)
+* package-b
+  - lib:package-b
+    * base >=3.0 && <3.5 (latest: 4.0.0.0)
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.project b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.project
new file mode 100644
index 0000000000..85abdb2be1
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.project
@@ -0,0 +1,4 @@
+packages: package-a
+          package-b
+
+constraints: base == 3.0.3.2
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.test.hs b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.test.hs
new file mode 100644
index 0000000000..65b9339959
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/cabal.test.hs
@@ -0,0 +1,27 @@
+import Test.Cabal.Prelude
+import System.Exit(ExitCode(..))
+
+
+main = cabalTest $ withRepo "repo" $ do
+  -- Test 1: Run from project root with no target specifier
+  result1 <- cabal' "outdated" ["all"]
+  assertOutputContains "package-a" result1
+  assertOutputContains "package-b" result1
+
+  -- Test 2: Run from project root with specific package target
+  result2 <- cabal' "v2-outdated" ["package-a"]
+  assertOutputContains "package-a" result2
+  assertOutputDoesNotContain "package-b" result2
+
+  -- Test 3: Run from project root with --simple-output flag
+  result3 <- cabal' "v2-outdated" ["all", "--simple-output"]
+  assertOutputContains "base" result3
+  assertOutputContains "template-haskell" result3
+
+  -- Test 4: Run from subdirectory
+  result4 <- cabal' "v2-outdated" ["--project-context"]
+  assertOutputContains "base" result4
+
+  -- Test 6: Test exit code behavior
+  result6 <- fails $ cabal' "v2-outdated" ["all", "--exit-code"]
+  assertExitCode (ExitFailure 1) result6
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/LICENSE b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/LICENSE
new file mode 100644
index 0000000000..92316cdd64
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2023, Cabal Test Suite
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Cabal Test Suite nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/package-a.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/package-a.cabal
new file mode 100644
index 0000000000..edc1301f76
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/package-a.cabal
@@ -0,0 +1,24 @@
+cabal-version:      2.4
+name:               package-a
+version:            0.1.0.0
+synopsis:           Package A for outdated command testing
+license:            BSD-3-Clause
+license-file:       LICENSE
+author:             Cabal Test Suite
+maintainer:         cabal-dev@haskell.org
+build-type:         Simple
+
+flag foo
+  description: test flag
+
+library
+  exposed-modules:    ModuleA
+  build-depends:      base >=3.2 && <3.3,
+                      binary == 0.8.6.0
+  if flag(foo)
+    build-depends: template-haskell == 2.3.0.*
+  else
+    build-depends: template-haskell == 2.3.*
+
+  hs-source-dirs:     src
+  default-language:   Haskell2010
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/src/ModuleA.hs b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/src/ModuleA.hs
new file mode 100644
index 0000000000..e1ed9f370a
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-a/src/ModuleA.hs
@@ -0,0 +1,4 @@
+module ModuleA where
+
+simpleFunction :: Int -> Int
+simpleFunction x = x + 1
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/LICENSE b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/LICENSE
new file mode 100644
index 0000000000..92316cdd64
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2023, Cabal Test Suite
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Cabal Test Suite nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/package-b.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/package-b.cabal
new file mode 100644
index 0000000000..619bca806c
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/package-b.cabal
@@ -0,0 +1,17 @@
+cabal-version:      2.4
+name:               package-b
+version:            0.1.0.0
+synopsis:           Package B for outdated command testing
+license:            BSD-3-Clause
+license-file:       LICENSE
+author:             Cabal Test Suite
+maintainer:         cabal-dev@haskell.org
+build-type:         Simple
+
+library
+  exposed-modules:    ModuleB
+  build-depends:      base >=3.0 && < 3.5,
+                      package-a,
+                      binary >=0.8 && <0.8.7
+  hs-source-dirs:     src
+  default-language:   Haskell2010
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/src/ModuleB.hs b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/src/ModuleB.hs
new file mode 100644
index 0000000000..9baf7dd49b
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/package-b/src/ModuleB.hs
@@ -0,0 +1,6 @@
+module ModuleB where
+
+import ModuleA
+
+anotherFunction :: Int -> Int
+anotherFunction x = simpleFunction (x * 2)
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.1/base.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.1/base.cabal
new file mode 100644
index 0000000000..3c7fb7a300
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.1/base.cabal
@@ -0,0 +1,154 @@
+name:           base
+version:        3.0.3.1
+license:        BSD3
+license-file:   LICENSE
+maintainer:     libraries@haskell.org
+synopsis:       Basic libraries (backwards-compatibility version)
+description:
+    This is a backwards-compatible version of the base package.
+    It depends on a later version of base, and was probably supplied
+    with your compiler when it was installed.
+
+cabal-version:  >=1.2
+build-type: Simple
+
+Library {
+    build-depends: base       >= 4.0 && < 4.2,
+                   syb        >= 0.1 && < 0.2
+    extensions: PackageImports
+
+    if impl(ghc < 6.9) {
+        buildable: False
+    }
+
+    if impl(ghc) {
+        exposed-modules:
+            Data.Generics,
+            Data.Generics.Aliases,
+            Data.Generics.Basics,
+            Data.Generics.Instances,
+            Data.Generics.Schemes,
+            Data.Generics.Text,
+            Data.Generics.Twins,
+            Foreign.Concurrent,
+            GHC.Arr,
+            GHC.Base,
+            GHC.Conc,
+            GHC.ConsoleHandler,
+            GHC.Desugar,
+            GHC.Dotnet,
+            GHC.Enum,
+            GHC.Environment,
+            GHC.Err,
+            GHC.Exception,
+            GHC.Exts,
+            GHC.Float,
+            GHC.ForeignPtr,
+            GHC.Handle,
+            GHC.IO,
+            GHC.IOBase,
+            GHC.Int,
+            GHC.List,
+            GHC.Num,
+            GHC.PArr,
+            GHC.Pack,
+            GHC.Ptr,
+            GHC.Read,
+            GHC.Real,
+            GHC.ST,
+            GHC.STRef,
+            GHC.Show,
+            GHC.Stable,
+            GHC.Storable,
+            GHC.TopHandler,
+            GHC.Unicode,
+            GHC.Weak,
+            GHC.Word,
+            System.Timeout
+    }
+    exposed-modules:
+        Control.Applicative,
+        Control.Arrow,
+        Control.Category,
+        Control.Concurrent,
+        Control.Concurrent.Chan,
+        Control.Concurrent.MVar,
+        Control.Concurrent.QSem,
+        Control.Concurrent.QSemN,
+        Control.Concurrent.SampleVar,
+        Control.Exception,
+        Control.Monad,
+        Control.Monad.Fix,
+        Control.Monad.Instances,
+        Control.Monad.ST,
+        Control.Monad.ST.Lazy,
+        Control.Monad.ST.Strict,
+        Data.Bits,
+        Data.Bool,
+        Data.Char,
+        Data.Complex,
+        Data.Dynamic,
+        Data.Either,
+        Data.Eq,
+        Data.Fixed,
+        Data.Foldable
+        Data.Function,
+        Data.HashTable,
+        Data.IORef,
+        Data.Int,
+        Data.Ix,
+        Data.List,
+        Data.Maybe,
+        Data.Monoid,
+        Data.Ord,
+        Data.Ratio,
+        Data.STRef,
+        Data.STRef.Lazy,
+        Data.STRef.Strict,
+        Data.String,
+        Data.Traversable
+        Data.Tuple,
+        Data.Typeable,
+        Data.Unique,
+        Data.Version,
+        Data.Word,
+        Debug.Trace,
+        Foreign,
+        Foreign.C,
+        Foreign.C.Error,
+        Foreign.C.String,
+        Foreign.C.Types,
+        Foreign.ForeignPtr,
+        Foreign.Marshal,
+        Foreign.Marshal.Alloc,
+        Foreign.Marshal.Array,
+        Foreign.Marshal.Error,
+        Foreign.Marshal.Pool,
+        Foreign.Marshal.Utils,
+        Foreign.Ptr,
+        Foreign.StablePtr,
+        Foreign.Storable,
+        Numeric,
+        Prelude,
+        System.Console.GetOpt,
+        System.CPUTime,
+        System.Environment,
+        System.Exit,
+        System.IO,
+        System.IO.Error,
+        System.IO.Unsafe,
+        System.Info,
+        System.Mem,
+        System.Mem.StableName,
+        System.Mem.Weak,
+        System.Posix.Internals,
+        System.Posix.Types,
+        Text.ParserCombinators.ReadP,
+        Text.ParserCombinators.ReadPrec,
+        Text.Printf,
+        Text.Read,
+        Text.Read.Lex,
+        Text.Show,
+        Text.Show.Functions
+        Unsafe.Coerce
+}
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.2/base.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.2/base.cabal
new file mode 100644
index 0000000000..1edd58ea0c
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-3.0.3.2/base.cabal
@@ -0,0 +1,160 @@
+name:           base
+version:        3.0.3.2
+license:        BSD3
+license-file:   LICENSE
+maintainer:     libraries@haskell.org
+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries/base
+synopsis:       Basic libraries (backwards-compatibility version)
+description:
+    This is a backwards-compatible version of the base package.
+    It depends on a later version of base, and was probably supplied
+    with your compiler when it was installed.
+
+cabal-version:  >=1.6
+build-type: Simple
+
+source-repository head
+    type:     darcs
+    location: http://darcs.haskell.org/packages/base3-compat
+
+Library {
+    build-depends: base       >= 4.0 && < 4.3,
+                   syb        >= 0.1 && < 0.2
+    extensions: PackageImports,CPP
+    ghc-options: -fno-warn-deprecations
+
+    if impl(ghc < 6.9) {
+        buildable: False
+    }
+
+    if impl(ghc) {
+        exposed-modules:
+            Data.Generics,
+            Data.Generics.Aliases,
+            Data.Generics.Basics,
+            Data.Generics.Instances,
+            Data.Generics.Schemes,
+            Data.Generics.Text,
+            Data.Generics.Twins,
+            Foreign.Concurrent,
+            GHC.Arr,
+            GHC.Base,
+            GHC.Conc,
+            GHC.ConsoleHandler,
+            GHC.Desugar,
+            GHC.Dotnet,
+            GHC.Enum,
+            GHC.Environment,
+            GHC.Err,
+            GHC.Exception,
+            GHC.Exts,
+            GHC.Float,
+            GHC.ForeignPtr,
+            GHC.Handle,
+            GHC.IO,
+            GHC.IOBase,
+            GHC.Int,
+            GHC.List,
+            GHC.Num,
+            GHC.PArr,
+            GHC.Pack,
+            GHC.Ptr,
+            GHC.Read,
+            GHC.Real,
+            GHC.ST,
+            GHC.STRef,
+            GHC.Show,
+            GHC.Stable,
+            GHC.Storable,
+            GHC.TopHandler,
+            GHC.Unicode,
+            GHC.Weak,
+            GHC.Word,
+            System.Timeout
+    }
+    exposed-modules:
+        Control.Applicative,
+        Control.Arrow,
+        Control.Category,
+        Control.Concurrent,
+        Control.Concurrent.Chan,
+        Control.Concurrent.MVar,
+        Control.Concurrent.QSem,
+        Control.Concurrent.QSemN,
+        Control.Concurrent.SampleVar,
+        Control.Exception,
+        Control.Monad,
+        Control.Monad.Fix,
+        Control.Monad.Instances,
+        Control.Monad.ST,
+        Control.Monad.ST.Lazy,
+        Control.Monad.ST.Strict,
+        Data.Bits,
+        Data.Bool,
+        Data.Char,
+        Data.Complex,
+        Data.Dynamic,
+        Data.Either,
+        Data.Eq,
+        Data.Fixed,
+        Data.Foldable
+        Data.Function,
+        Data.HashTable,
+        Data.IORef,
+        Data.Int,
+        Data.Ix,
+        Data.List,
+        Data.Maybe,
+        Data.Monoid,
+        Data.Ord,
+        Data.Ratio,
+        Data.STRef,
+        Data.STRef.Lazy,
+        Data.STRef.Strict,
+        Data.String,
+        Data.Traversable
+        Data.Tuple,
+        Data.Typeable,
+        Data.Unique,
+        Data.Version,
+        Data.Word,
+        Debug.Trace,
+        Foreign,
+        Foreign.C,
+        Foreign.C.Error,
+        Foreign.C.String,
+        Foreign.C.Types,
+        Foreign.ForeignPtr,
+        Foreign.Marshal,
+        Foreign.Marshal.Alloc,
+        Foreign.Marshal.Array,
+        Foreign.Marshal.Error,
+        Foreign.Marshal.Pool,
+        Foreign.Marshal.Utils,
+        Foreign.Ptr,
+        Foreign.StablePtr,
+        Foreign.Storable,
+        Numeric,
+        Prelude,
+        System.Console.GetOpt,
+        System.CPUTime,
+        System.Environment,
+        System.Exit,
+        System.IO,
+        System.IO.Error,
+        System.IO.Unsafe,
+        System.Info,
+        System.Mem,
+        System.Mem.StableName,
+        System.Mem.Weak,
+        System.Posix.Internals,
+        System.Posix.Types,
+        Text.ParserCombinators.ReadP,
+        Text.ParserCombinators.ReadPrec,
+        Text.Printf,
+        Text.Read,
+        Text.Read.Lex,
+        Text.Show,
+        Text.Show.Functions
+        Unsafe.Coerce
+}
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-4.0.0.0/base.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-4.0.0.0/base.cabal
new file mode 100644
index 0000000000..1aa8333373
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/base-4.0.0.0/base.cabal
@@ -0,0 +1,174 @@
+name:           base
+version:        4.0.0.0
+license:        BSD3
+license-file:   LICENSE
+maintainer:     libraries@haskell.org
+synopsis:       Basic libraries
+description:
+    This package contains the Prelude and its support libraries,
+    and a large collection of useful libraries ranging from data
+    structures to parsing combinators and debugging utilities.
+cabal-version: >= 1.2.3
+build-type: Configure
+extra-tmp-files:
+                config.log config.status autom4te.cache
+                include/HsBaseConfig.h
+extra-source-files:
+                config.guess config.sub install-sh
+                aclocal.m4 configure.ac configure
+                include/CTypes.h
+
+Library {
+    if impl(ghc) {
+        build-depends: rts, ghc-prim, integer
+        exposed-modules:
+            Foreign.Concurrent,
+            GHC.Arr,
+            GHC.Base,
+            GHC.Classes,
+            GHC.Conc,
+            GHC.ConsoleHandler,
+            GHC.Desugar,
+            GHC.Enum,
+            GHC.Environment,
+            GHC.Err,
+            GHC.Exception,
+            GHC.Exts,
+            GHC.Float,
+            GHC.ForeignPtr,
+            GHC.Handle,
+            GHC.IO,
+            GHC.IOBase,
+            GHC.Int,
+            GHC.List,
+            GHC.Num,
+            GHC.PArr,
+            GHC.Pack,
+            GHC.Ptr,
+            GHC.Read,
+            GHC.Real,
+            GHC.ST,
+            GHC.STRef,
+            GHC.Show,
+            GHC.Stable,
+            GHC.Storable,
+            GHC.TopHandler,
+            GHC.Unicode,
+            GHC.Weak,
+            GHC.Word,
+            System.Timeout
+        extensions: MagicHash, ExistentialQuantification, Rank2Types,
+                    ScopedTypeVariables, UnboxedTuples,
+                    ForeignFunctionInterface, UnliftedFFITypes,
+                    DeriveDataTypeable, GeneralizedNewtypeDeriving,
+                    FlexibleInstances, PatternSignatures, StandaloneDeriving,
+                    PatternGuards, EmptyDataDecls
+    }
+    exposed-modules:
+        Control.Applicative,
+        Control.Arrow,
+        Control.Category,
+        Control.Concurrent,
+        Control.Concurrent.Chan,
+        Control.Concurrent.MVar,
+        Control.Concurrent.QSem,
+        Control.Concurrent.QSemN,
+        Control.Concurrent.SampleVar,
+        Control.Exception,
+        Control.Exception.Base
+        Control.OldException,
+        Control.Monad,
+        Control.Monad.Fix,
+        Control.Monad.Instances,
+        Control.Monad.ST
+        Control.Monad.ST.Lazy
+        Control.Monad.ST.Strict
+        Data.Bits,
+        Data.Bool,
+        Data.Char,
+        Data.Complex,
+        Data.Dynamic,
+        Data.Either,
+        Data.Eq,
+        Data.Data,
+        Data.Fixed,
+        Data.Foldable
+        Data.Function,
+        Data.HashTable,
+        Data.IORef,
+        Data.Int,
+        Data.Ix,
+        Data.List,
+        Data.Maybe,
+        Data.Monoid,
+        Data.Ord,
+        Data.Ratio,
+        Data.STRef
+        Data.STRef.Lazy
+        Data.STRef.Strict
+        Data.String,
+        Data.Traversable
+        Data.Tuple,
+        Data.Typeable,
+        Data.Unique,
+        Data.Version,
+        Data.Word,
+        Debug.Trace,
+        Foreign,
+        Foreign.C,
+        Foreign.C.Error,
+        Foreign.C.String,
+        Foreign.C.Types,
+        Foreign.ForeignPtr,
+        Foreign.Marshal,
+        Foreign.Marshal.Alloc,
+        Foreign.Marshal.Array,
+        Foreign.Marshal.Error,
+        Foreign.Marshal.Pool,
+        Foreign.Marshal.Utils,
+        Foreign.Ptr,
+        Foreign.StablePtr,
+        Foreign.Storable,
+        Numeric,
+        Prelude,
+        System.Console.GetOpt
+        System.CPUTime,
+        System.Environment,
+        System.Exit,
+        System.IO,
+        System.IO.Error,
+        System.IO.Unsafe,
+        System.Info,
+        System.Mem,
+        System.Mem.StableName,
+        System.Mem.Weak,
+        System.Posix.Internals,
+        System.Posix.Types,
+        Text.ParserCombinators.ReadP,
+        Text.ParserCombinators.ReadPrec,
+        Text.Printf,
+        Text.Read,
+        Text.Read.Lex,
+        Text.Show,
+        Text.Show.Functions
+        Unsafe.Coerce
+    c-sources:
+        cbits/PrelIOUtils.c
+        cbits/WCsubst.c
+        cbits/Win32Utils.c
+        cbits/consUtils.c
+        cbits/dirUtils.c
+        cbits/inputReady.c
+        cbits/selectUtils.c
+    include-dirs: include
+    includes:    HsBase.h
+    install-includes:    HsBase.h HsBaseConfig.h WCsubst.h dirUtils.h consUtils.h Typeable.h
+    if os(windows) {
+        extra-libraries: wsock32, msvcrt, kernel32, user32, shell32
+    }
+    extensions: CPP
+    -- We need to set the package name to base (without a version number)
+    -- as it's magic.
+    ghc-options: -package-name base
+    nhc98-options: -H4M -K3M
+}
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.5.0/binary.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.5.0/binary.cabal
new file mode 100644
index 0000000000..b0ab2b24ec
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.5.0/binary.cabal
@@ -0,0 +1,35 @@
+name:            binary
+version:         0.8.5.0
+license:         BSD3
+license-file:    LICENSE
+author:          Lennart Kolmodin <kolmodin@gmail.com>
+maintainer:      Lennart Kolmodin, Don Stewart <dons00@gmail.com>
+homepage:        https://github.com/kolmodin/binary
+description:     Efficient, pure binary serialisation using lazy ByteStrings.
+                 Haskell values may be encoded to and from binary formats,
+                 written to disk as binary, or sent over the network.
+                 The format used can be automatically generated, or
+                 you can choose to implement a custom format if needed.
+                 Serialisation speeds of over 1 G\/sec have been observed,
+                 so this library should be suitable for high performance
+                 scenarios.
+synopsis:        Binary serialisation for Haskell values using lazy ByteStrings
+category:        Data, Parsing
+stability:       provisional
+build-type:      Simple
+cabal-version:   >= 1.8
+
+library
+  build-depends:   base >= 3 && < 5, bytestring >= 0.8.4, containers, array
+  hs-source-dirs:  src
+  exposed-modules: Data.Binary,
+                   Data.Binary.Put,
+                   Data.Binary.Get,
+                   Data.Binary.Get.Internal,
+                   Data.Binary.Builder
+
+  other-modules:   Data.Binary.Class,
+                   Data.Binary.Internal,
+                   Data.Binary.Generic,
+                   Data.Binary.FloatCast
+  ghc-options:     -O2 -Wall -fliberate-case-threshold=1000
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.6.0/binary.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.6.0/binary.cabal
new file mode 100644
index 0000000000..caa10cb223
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.8.6.0/binary.cabal
@@ -0,0 +1,35 @@
+name:            binary
+version:         0.8.6.0
+license:         BSD3
+license-file:    LICENSE
+author:          Lennart Kolmodin <kolmodin@gmail.com>
+maintainer:      Lennart Kolmodin, Don Stewart <dons00@gmail.com>
+homepage:        https://github.com/kolmodin/binary
+description:     Efficient, pure binary serialisation using lazy ByteStrings.
+                 Haskell values may be encoded to and from binary formats,
+                 written to disk as binary, or sent over the network.
+                 The format used can be automatically generated, or
+                 you can choose to implement a custom format if needed.
+                 Serialisation speeds of over 1 G\/sec have been observed,
+                 so this library should be suitable for high performance
+                 scenarios.
+synopsis:        Binary serialisation for Haskell values using lazy ByteStrings
+category:        Data, Parsing
+stability:       provisional
+build-type:      Simple
+cabal-version:   >= 1.8
+
+library
+  build-depends:   base >= 3 && < 5, bytestring >= 0.8.4, containers, array
+  hs-source-dirs:  src
+  exposed-modules: Data.Binary,
+                   Data.Binary.Put,
+                   Data.Binary.Get,
+                   Data.Binary.Get.Internal,
+                   Data.Binary.Builder
+
+  other-modules:   Data.Binary.Class,
+                   Data.Binary.Internal,
+                   Data.Binary.Generic,
+                   Data.Binary.FloatCast
+  ghc-options:     -O2 -Wall -fliberate-case-threshold=1000
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.9.0.0/binary.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.9.0.0/binary.cabal
new file mode 100644
index 0000000000..66485f6f76
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/binary-0.9.0.0/binary.cabal
@@ -0,0 +1,35 @@
+name:            binary
+version:         0.9.0.0
+license:         BSD3
+license-file:    LICENSE
+author:          Lennart Kolmodin <kolmodin@gmail.com>
+maintainer:      Lennart Kolmodin, Don Stewart <dons00@gmail.com>
+homepage:        https://github.com/kolmodin/binary
+description:     Efficient, pure binary serialisation using lazy ByteStrings.
+                 Haskell values may be encoded to and from binary formats,
+                 written to disk as binary, or sent over the network.
+                 The format used can be automatically generated, or
+                 you can choose to implement a custom format if needed.
+                 Serialisation speeds of over 1 G\/sec have been observed,
+                 so this library should be suitable for high performance
+                 scenarios.
+synopsis:        Binary serialisation for Haskell values using lazy ByteStrings
+category:        Data, Parsing
+stability:       provisional
+build-type:      Simple
+cabal-version:   >= 1.8
+
+library
+  build-depends:   base >= 3 && < 5, bytestring >= 0.8.4, containers, array
+  hs-source-dirs:  src
+  exposed-modules: Data.Binary,
+                   Data.Binary.Put,
+                   Data.Binary.Get,
+                   Data.Binary.Get.Internal,
+                   Data.Binary.Builder
+
+  other-modules:   Data.Binary.Class,
+                   Data.Binary.Internal,
+                   Data.Binary.Generic,
+                   Data.Binary.FloatCast
+  ghc-options:     -O2 -Wall -fliberate-case-threshold=1000
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/preferred-versions b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/preferred-versions
new file mode 100644
index 0000000000..5be791d3d0
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/preferred-versions
@@ -0,0 +1 @@
+binary <0.9.0.0 || >0.9.0.0
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.0/template-haskell.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.0/template-haskell.cabal
new file mode 100644
index 0000000000..064cb9d51b
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.0/template-haskell.cabal
@@ -0,0 +1,22 @@
+name:       template-haskell
+version:    2.3.0.0
+x-revision: 1
+license:    BSD3
+license-file:   LICENSE
+maintainer: libraries@haskell.org
+description:
+    Facilities for manipulating Haskell source code using Template Haskell.
+build-type: Simple
+build-depends: base<4.3, pretty, packedstring, containers
+exposed-modules:
+    Language.Haskell.TH.Syntax,
+    Language.Haskell.TH.PprLib,
+    Language.Haskell.TH.Ppr,
+    Language.Haskell.TH.Lib,
+    Language.Haskell.TH.Quote,
+    Language.Haskell.TH
+extensions: MagicHash, PatternGuards, PolymorphicComponents,
+            DeriveDataTypeable, TypeSynonymInstances
+-- We need to set the package name to template-haskell (without a
+-- version number) as it's magic.
+ghc-options: -package-name template-haskell
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.1/template-haskell.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.1/template-haskell.cabal
new file mode 100644
index 0000000000..8fbe6b269a
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.3.0.1/template-haskell.cabal
@@ -0,0 +1,22 @@
+name:       template-haskell
+version:    2.3.0.1
+x-revision: 1
+license:    BSD3
+license-file:   LICENSE
+maintainer: libraries@haskell.org
+description:
+    Facilities for manipulating Haskell source code using Template Haskell.
+build-type: Simple
+build-depends: base <4.3, pretty, packedstring, containers
+exposed-modules:
+    Language.Haskell.TH.Syntax,
+    Language.Haskell.TH.PprLib,
+    Language.Haskell.TH.Ppr,
+    Language.Haskell.TH.Lib,
+    Language.Haskell.TH.Quote,
+    Language.Haskell.TH
+extensions: MagicHash, PatternGuards, PolymorphicComponents,
+            DeriveDataTypeable, TypeSynonymInstances
+-- We need to set the package name to template-haskell (without a
+-- version number) as it's magic.
+ghc-options: -package-name template-haskell
diff --git a/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.4.0.0/template-haskell.cabal b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.4.0.0/template-haskell.cabal
new file mode 100644
index 0000000000..4c5ee3cf3a
--- /dev/null
+++ b/cabal-testsuite/PackageTests/Outdated/Issue8283/repo/template-haskell-2.4.0.0/template-haskell.cabal
@@ -0,0 +1,32 @@
+name:       template-haskell
+version:    2.4.0.0
+x-revision: 1
+license:    BSD3
+license-file:   LICENSE
+maintainer: libraries@haskell.org
+bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=Template%20Haskell
+description:
+    Facilities for manipulating Haskell source code using Template Haskell.
+build-type: Simple
+Cabal-Version: >= 1.6
+
+Library
+    build-depends: base >= 3 && < 4.3,
+                   pretty, containers
+    exposed-modules:
+        Language.Haskell.TH.Syntax.Internals
+        Language.Haskell.TH.Syntax
+        Language.Haskell.TH.PprLib
+        Language.Haskell.TH.Ppr
+        Language.Haskell.TH.Lib
+        Language.Haskell.TH.Quote
+        Language.Haskell.TH
+    extensions: MagicHash, PatternGuards, PolymorphicComponents,
+                DeriveDataTypeable, TypeSynonymInstances
+    -- We need to set the package name to template-haskell (without a
+    -- version number) as it's magic.
+    ghc-options: -package-name template-haskell
+
+source-repository head
+    type:     darcs
+    location: http://darcs.haskell.org/packages/template-haskell/
diff --git a/cabal-testsuite/PackageTests/Outdated/outdated-project-file.out b/cabal-testsuite/PackageTests/Outdated/outdated-project-file.out
index 186bab610c..82fedb3671 100644
--- a/cabal-testsuite/PackageTests/Outdated/outdated-project-file.out
+++ b/cabal-testsuite/PackageTests/Outdated/outdated-project-file.out
@@ -1,11 +1,28 @@
 # cabal v2-update
 Downloading the latest package list from test-local-repo
 # cabal outdated
+Configuration is affected by the following files:
+- variant.project
+- variant.project.freeze
 Outdated dependencies:
-base ==3.0.3.2 (latest: 4.0.0.0)
+* project-config
+  - project config variant.project.freeze
+    * base ==3.0.3.2 (latest: 4.0.0.0)
 # cabal outdated
+Configuration is affected by the following files:
+- variant.project
+- variant.project.freeze
 Outdated dependencies:
-base ==3.0.3.2 (latest: 4.0.0.0)
+* project-config
+  - project config variant.project.freeze
+    * base ==3.0.3.2 (latest: 4.0.0.0)
 # cabal outdated
-Error: [Cabal-7103]
---project-dir and --project-file must only be used with --v2-freeze-file.
+Configuration is affected by the following files:
+- variant.project
+- variant.project.freeze
+Outdated dependencies:
+* my
+  - lib:my
+    * base >=3 && <4 (latest: 4.0.0.0)
+  - test:tests-Foo
+    * template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0)
diff --git a/cabal-testsuite/PackageTests/Outdated/outdated-project-file.test.hs b/cabal-testsuite/PackageTests/Outdated/outdated-project-file.test.hs
index 84c2a1d58c..6dbce3d264 100644
--- a/cabal-testsuite/PackageTests/Outdated/outdated-project-file.test.hs
+++ b/cabal-testsuite/PackageTests/Outdated/outdated-project-file.test.hs
@@ -11,5 +11,4 @@ main = cabalTest $ withRepo "repo" $ do
   assertOutputDoesNotContain "template-haskell" res
   assertOutputDoesNotContain "binary" res
 
-  -- Test for erroring on --project-file without --v2-freeze-file
-  fails $ cabal "outdated" ["--project-file", "variant.project"]
+  cabal "outdated" ["--project-file", "variant.project"]
diff --git a/cabal-testsuite/PackageTests/Outdated/outdated.out b/cabal-testsuite/PackageTests/Outdated/outdated.out
index b11fae3c32..ba11ee4243 100644
--- a/cabal-testsuite/PackageTests/Outdated/outdated.out
+++ b/cabal-testsuite/PackageTests/Outdated/outdated.out
@@ -1,16 +1,38 @@
 # cabal v2-update
 Downloading the latest package list from test-local-repo
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 Outdated dependencies:
-base >=3 && <4 (latest: 4.0.0.0)
-template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0)
+* my
+  - lib:my
+    * base >=3 && <4 (latest: 4.0.0.0)
+  - test:tests-Foo
+    * template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0)
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 Outdated dependencies:
-template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0)
+* my
+  - test:tests-Foo
+    * template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0)
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 All dependencies are up to date.
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 Outdated dependencies:
-template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0)
+* my
+  - test:tests-Foo
+    * template-haskell >=2.3.0.0 && <2.4 (latest: 2.4.0.0)
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 All dependencies are up to date.
diff --git a/cabal-testsuite/PackageTests/Outdated/outdated_freeze.out b/cabal-testsuite/PackageTests/Outdated/outdated_freeze.out
index d417b8dfe7..bf0a44ada6 100644
--- a/cabal-testsuite/PackageTests/Outdated/outdated_freeze.out
+++ b/cabal-testsuite/PackageTests/Outdated/outdated_freeze.out
@@ -1,29 +1,54 @@
 # cabal v2-update
 Downloading the latest package list from test-local-repo
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 Outdated dependencies:
-base ==3.0.3.2 (latest: 4.0.0.0)
-template-haskell ==2.3.0.0 (latest: 2.4.0.0)
-binary ==0.8.5.0 (latest: 0.8.6.0)
+* project-config
+  - project config cabal.project.freeze
+    * base ==3.0.3.2 (latest: 4.0.0.0)
+    * binary ==0.8.5.0 (latest: 0.8.6.0)
+    * template-haskell ==2.3.0.0 (latest: 2.4.0.0)
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 All dependencies are up to date.
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 Outdated dependencies:
-template-haskell ==2.3.0.0 (latest: 2.3.0.1)
-binary ==0.8.5.0 (latest: 0.8.6.0)
+* project-config
+  - project config cabal.project.freeze
+    * binary ==0.8.5.0 (latest: 0.8.6.0)
+    * template-haskell ==2.3.0.0 (latest: 2.3.0.1)
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 Outdated dependencies:
-base ==3.0.3.2 (latest: 4.0.0.0)
-template-haskell ==2.3.0.0 (latest: 2.4.0.0)
-binary ==0.8.5.0 (latest: 0.8.6.0)
+* project-config
+  - user config  <ROOT>/cabal.config
+    * base ==3.0.3.2 (latest: 4.0.0.0)
+    * binary ==0.8.5.0 (latest: 0.8.6.0)
+    * template-haskell ==2.3.0.0 (latest: 2.4.0.0)
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 All dependencies are up to date.
 # cabal outdated
+Configuration is affected by the following files:
+- cabal.project
+- cabal.project.freeze
 Outdated dependencies:
-template-haskell ==2.3.0.0 (latest: 2.3.0.1)
-binary ==0.8.5.0 (latest: 0.8.6.0)
+* project-config
+  - user config  <ROOT>/cabal.config
+    * binary ==0.8.5.0 (latest: 0.8.6.0)
+    * template-haskell ==2.3.0.0 (latest: 2.3.0.1)
 # cabal outdated
-Error: [Cabal-7104]
-Couldn't find a freeze file expected at: <ROOT>/cabal.project.missing.freeze.freeze
-
-We are looking for this file because you supplied '--project-file' or '--v2-freeze-file'. When one of these flags is given, we try to read the dependencies from a freeze file. If it is undesired behaviour, you should not use these flags, otherwise please generate a freeze file via 'cabal freeze'.
+Configuration is affected by the following files:
+- cabal.project.missing.freeze
+All dependencies are up to date.
diff --git a/cabal-testsuite/PackageTests/Outdated/outdated_freeze.test.hs b/cabal-testsuite/PackageTests/Outdated/outdated_freeze.test.hs
index 35756590ea..175b74d7b3 100644
--- a/cabal-testsuite/PackageTests/Outdated/outdated_freeze.test.hs
+++ b/cabal-testsuite/PackageTests/Outdated/outdated_freeze.test.hs
@@ -19,5 +19,5 @@ main = cabalTest $ withRepo "repo" $ do
           assertOutputContains "template-haskell" out
           assertOutputContains "binary" out)
 
-  fails $ cabal' "outdated" ["--project-file=cabal.project.missing.freeze", "--v2-freeze-file"]
+  cabal' "outdated" ["--project-file=cabal.project.missing.freeze", "--v2-freeze-file"]
   return ()
diff --git a/cabal.project b/cabal.project
index a2075cfdc2..21f5af4a09 100644
--- a/cabal.project
+++ b/cabal.project
@@ -3,7 +3,9 @@ import: project-cabal/ghc-latest.config
 import: project-cabal/pkgs.config
 import: project-cabal/constraints.config
 
-tests: True
+tests: False
+
+multi-repl: True
 
 -- if you are developing on a system without TH, use a `cabal.project.local`
 -- to disable this
-- 
GitLab