Brandon Chinn pushed to branch wip/T21730-import at Glasgow Haskell Compiler / GHC

Commits:

14 changed files:

Changes:

  • compiler/GHC.hs
    ... ... @@ -1503,7 +1503,8 @@ availsToGlobalRdrEnv hsc_env mod avails
    1503 1503
           -- all the specified modules into the global interactive module
    
    1504 1504
         imp_spec = ImpSpec { is_decl = decl, is_item = ImpAll}
    
    1505 1505
         decl = ImpDeclSpec { is_mod = mod, is_as = moduleName mod,
    
    1506
    -                         is_qual = False, is_isboot = NotBoot, is_pkg_qual = NoPkgQual,
    
    1506
    +                         is_qual = False, is_implicit = False,
    
    1507
    +                         is_isboot = NotBoot, is_pkg_qual = NoPkgQual,
    
    1507 1508
                              is_dloc = srcLocSpan interactiveSrcLoc,
    
    1508 1509
                              is_level = NormalLevel }
    
    1509 1510
     
    

  • compiler/GHC/Hs/ImpExp.hs
    ... ... @@ -80,14 +80,19 @@ type instance XCImportDecl GhcTc = DataConCantHappen
    80 80
     data XImportDeclPass = XImportDeclPass
    
    81 81
         { ideclAnn        :: EpAnn EpAnnImportDecl
    
    82 82
         , ideclSourceText :: SourceText -- Note [Pragma source text] in "GHC.Types.SourceText"
    
    83
    -    , ideclImplicit   :: Bool
    
    84
    -        -- ^ GHC generates an `ImportDecl` to represent the invisible `import Prelude`
    
    85
    -        -- that appears in any file that omits `import Prelude`, setting
    
    86
    -        -- this field to indicate that the import doesn't appear in the
    
    87
    -        -- original source. True => implicit import (of Prelude)
    
    83
    +    , ideclImplicit   :: Bool -- ^ See Note [Implicit imports]
    
    88 84
         }
    
    89 85
         deriving (Data)
    
    90 86
     
    
    87
    +{- Note [Implicit imports]
    
    88
    +~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    89
    +
    
    90
    +GHC generates an `ImportDecl` to represent the invisible `import Prelude`
    
    91
    +that appears in any file that omits `import Prelude`, setting
    
    92
    +this field to indicate that the import doesn't appear in the
    
    93
    +original source. True => implicit import (of Prelude)
    
    94
    +-}
    
    95
    +
    
    91 96
     type instance XXImportDecl  (GhcPass _) = DataConCantHappen
    
    92 97
     
    
    93 98
     type instance Anno ModuleName = SrcSpanAnnA
    

  • compiler/GHC/Rename/Env.hs
    ... ... @@ -1982,6 +1982,7 @@ lookupQualifiedNameGHCi fos rdr_name
    1982 1982
                                  , is_as = moduleName mod
    
    1983 1983
                                  , is_pkg_qual = NoPkgQual
    
    1984 1984
                                  , is_qual = True
    
    1985
    +                             , is_implicit = False
    
    1985 1986
                                  , is_isboot = NotBoot
    
    1986 1987
                                  , is_dloc = noSrcSpan
    
    1987 1988
                                  , is_level = NormalLevel }
    

  • compiler/GHC/Rename/Names.hs
    ... ... @@ -391,7 +391,7 @@ rnImportDecl this_mod
    391 391
     
    
    392 392
         let imp_mod = mi_module iface
    
    393 393
             qual_mod_name = fmap unLoc as_mod `orElse` imp_mod_name
    
    394
    -        imp_spec  = ImpDeclSpec { is_mod = imp_mod, is_qual = qual_only,
    
    394
    +        imp_spec  = ImpDeclSpec { is_mod = imp_mod, is_qual = qual_only, is_implicit = implicit,
    
    395 395
                                       is_dloc = locA loc, is_as = qual_mod_name,
    
    396 396
                                       is_pkg_qual = pkg_qual, is_isboot = want_boot,
    
    397 397
                                       is_level = convImportLevel import_level }
    
    ... ... @@ -2014,40 +2014,38 @@ The ImportMap is a short-lived intermediate data structure records, for
    2014 2014
     each import declaration, what stuff brought into scope by that
    
    2015 2015
     declaration is actually used in the module.
    
    2016 2016
     
    
    2017
    -The SrcLoc is the location of the END of a particular 'import'
    
    2018
    -declaration.  Why *END*?  Because we don't want to get confused
    
    2019
    -by the implicit Prelude import. Consider (#7476) the module
    
    2020
    -    import Foo( foo )
    
    2021
    -    main = print foo
    
    2022
    -There is an implicit 'import Prelude(print)', and it gets a SrcSpan
    
    2023
    -of line 1:1 (just the point, not a span). If we use the *START* of
    
    2024
    -the SrcSpan to identify the import decl, we'll confuse the implicit
    
    2025
    -import Prelude with the explicit 'import Foo'.  So we use the END.
    
    2026
    -It's just a cheap hack; we could equally well use the Span too.
    
    2027
    -
    
    2028 2017
     The [GlobalRdrElt] are the things imported from that decl.
    
    2029 2018
     -}
    
    2030 2019
     
    
    2031
    -type ImportMap = Map RealSrcLoc [GlobalRdrElt]  -- See [The ImportMap]
    
    2032
    -     -- If loc :-> gres, then
    
    2033
    -     --   'loc' = the end loc of the bestImport of each GRE in 'gres'
    
    2020
    +data ImportMap = ImportMap
    
    2021
    +  { im_imports :: Map RealSrcSpan [GlobalRdrElt]
    
    2022
    +    -- ^ See [The ImportMap]
    
    2023
    +    -- If loc :-> gres, then
    
    2024
    +    --   'loc' = the end loc of the bestImport of each GRE in 'gres'
    
    2025
    +  , im_implicitImports :: Map ModuleName [GlobalRdrElt]
    
    2026
    +  , im_generatedImports :: Map ModuleName [GlobalRdrElt]
    
    2027
    +  }
    
    2034 2028
     
    
    2035 2029
     mkImportMap :: [GlobalRdrElt] -> ImportMap
    
    2036 2030
     -- For each of a list of used GREs, find all the import decls that brought
    
    2037 2031
     -- it into scope; choose one of them (bestImport), and record
    
    2038 2032
     -- the RdrName in that import decl's entry in the ImportMap
    
    2039
    -mkImportMap = foldr insertImportMap Map.empty
    
    2033
    +mkImportMap = foldr insertImportMap $ ImportMap Map.empty Map.empty Map.empty
    
    2040 2034
     
    
    2041 2035
     insertImportMap :: GlobalRdrElt -> ImportMap -> ImportMap
    
    2042
    -insertImportMap gre@(GRE { gre_imp = imp_specs }) importMap =
    
    2043
    -  case toImportMapSrcLoc (is_dloc (is_decl best_imp_spec)) of
    
    2044
    -    Just decl_loc -> insertElem decl_loc gre importMap
    
    2045
    -    Nothing -> importMap
    
    2036
    +insertImportMap gre@(GRE { gre_imp = imp_specs }) importMap
    
    2037
    +  | is_implicit best_imp_spec =
    
    2038
    +      importMap{im_implicitImports = insertElem (moduleName $ is_mod best_imp_spec) gre $ im_implicitImports importMap}
    
    2039
    +  | RealSrcSpan importSpan _ <- is_dloc best_imp_spec =
    
    2040
    +      importMap{im_imports = insertElem importSpan gre $ im_imports importMap}
    
    2041
    +  | UnhelpfulSpan UnhelpfulGenerated <- is_dloc best_imp_spec =
    
    2042
    +      importMap{im_generatedImports = insertElem (moduleName $ is_mod best_imp_spec) gre $ im_generatedImports importMap}
    
    2043
    +  | otherwise = importMap
    
    2046 2044
       where
    
    2047 2045
         best_imp_spec =
    
    2048 2046
           case bagToList imp_specs of
    
    2049 2047
             []     -> pprPanic "mkImportMap: GRE with no ImportSpecs" (ppr gre)
    
    2050
    -        is:iss -> bestImport (is NE.:| iss)
    
    2048
    +        is:iss -> is_decl $ bestImport (is NE.:| iss)
    
    2051 2049
     
    
    2052 2050
         -- https://github.com/haskell/containers/issues/784
    
    2053 2051
         insertElem :: Ord k => k -> v -> Map k [v] -> Map k [v]
    
    ... ... @@ -2056,16 +2054,14 @@ insertImportMap gre@(GRE { gre_imp = imp_specs }) importMap =
    2056 2054
           Nothing -> Just [v]
    
    2057 2055
     
    
    2058 2056
     lookupImportMap :: LImportDecl GhcRn -> ImportMap -> [GlobalRdrElt]
    
    2059
    -lookupImportMap (L srcSpan _) importMap =
    
    2057
    +lookupImportMap (L srcSpan ImportDecl{ideclName = L _ modName}) importMap =
    
    2060 2058
       fromMaybe [] $
    
    2061
    -    toImportMapSrcLoc (locA srcSpan) >>= (`Map.lookup` importMap)
    
    2062
    -
    
    2063
    -toImportMapSrcLoc :: SrcSpan -> Maybe RealSrcLoc
    
    2064
    -toImportMapSrcLoc srcSpan =
    
    2065
    -  -- see Note [The ImportMap] for why we're using srcSpanEnd
    
    2066
    -  case srcSpanEnd srcSpan of
    
    2067
    -    RealSrcLoc loc _ -> Just loc
    
    2068
    -    UnhelpfulLoc _ -> Nothing
    
    2059
    +    -- should match logic in insertImportMap
    
    2060
    +    case locA srcSpan of
    
    2061
    +      _ | Just gres <- modName `Map.lookup` im_implicitImports importMap -> Just gres
    
    2062
    +      RealSrcSpan realSrcSpan _ -> realSrcSpan `Map.lookup` im_imports importMap
    
    2063
    +      UnhelpfulSpan UnhelpfulGenerated -> modName `Map.lookup` im_generatedImports importMap
    
    2064
    +      _ -> Nothing
    
    2069 2065
     
    
    2070 2066
     warnUnusedImport :: GlobalRdrEnv -> ImportDeclUsage -> RnM ()
    
    2071 2067
     warnUnusedImport rdr_env (L loc decl, used, unused)
    

  • compiler/GHC/Runtime/Loader.hs
    ... ... @@ -354,7 +354,8 @@ lookupRdrNameInModuleForPlugins hsc_env mod_name rdr_name = do
    354 354
                     Just iface -> do
    
    355 355
                         -- Try and find the required name in the exports
    
    356 356
                         let decl_spec = ImpDeclSpec { is_mod = mod, is_as = mod_name, is_pkg_qual = NoPkgQual
    
    357
    -                                                , is_qual = False, is_dloc = noSrcSpan, is_isboot = NotBoot, is_level = SpliceLevel }
    
    357
    +                                                , is_qual = False, is_implicit = False
    
    358
    +                                                , is_dloc = noSrcSpan, is_isboot = NotBoot, is_level = SpliceLevel }
    
    358 359
                             imp_spec = ImpSpec decl_spec ImpAll
    
    359 360
                             env = mkGlobalRdrEnv
    
    360 361
                                 $ gresFromAvails hsc_env (Just imp_spec) (mi_exports iface)
    

  • compiler/GHC/Tc/Utils/Backpack.hs
    ... ... @@ -633,6 +633,7 @@ mergeSignatures
    633 633
                                                 is_as       = mod_name,
    
    634 634
                                                 is_pkg_qual = NoPkgQual,
    
    635 635
                                                 is_qual     = False,
    
    636
    +                                            is_implicit = False,
    
    636 637
                                                 is_isboot   = NotBoot,
    
    637 638
                                                 is_dloc     = locA loc,
    
    638 639
                                                 is_level    = NormalLevel
    

  • compiler/GHC/Types/Name/Reader.hs
    ... ... @@ -1821,6 +1821,7 @@ shadowNames drop_only_qualified env new_gres = minusOccEnv_C_Ns do_shadowing env
    1821 1821
                                        , is_as = old_mod_name
    
    1822 1822
                                        , is_pkg_qual = NoPkgQual
    
    1823 1823
                                        , is_qual = True
    
    1824
    +                                   , is_implicit = False
    
    1824 1825
                                        , is_level = NormalLevel -- MP: Not 100% sure this is correct
    
    1825 1826
                                        , is_isboot = NotBoot
    
    1826 1827
                                        , is_dloc = greDefinitionSrcSpan old_gre }
    
    ... ... @@ -1983,6 +1984,7 @@ data ImpDeclSpec
    1983 1984
             is_as       :: !ModuleName, -- ^ Import alias, e.g. from @as M@ (or @Muggle@ if there is no @as@ clause)
    
    1984 1985
             is_pkg_qual :: !PkgQual,    -- ^ Was this a package import?
    
    1985 1986
             is_qual     :: !Bool,       -- ^ Was this import qualified?
    
    1987
    +        is_implicit :: !Bool,       -- ^ Was this import implicit? See Note [Implicit imports]
    
    1986 1988
             is_dloc     :: !SrcSpan,    -- ^ The location of the entire import declaration
    
    1987 1989
             is_isboot   :: !IsBootInterface, -- ^ Was this a SOURCE import?
    
    1988 1990
             is_level    :: !ImportLevel -- ^ Was this import level modified? splice/quote +-1
    
    ... ... @@ -1995,11 +1997,12 @@ instance NFData ImpDeclSpec where
    1995 1997
     
    
    1996 1998
     
    
    1997 1999
     instance Binary ImpDeclSpec where
    
    1998
    -  put_ bh (ImpDeclSpec mod as pkg_qual qual _dloc isboot isstage) = do
    
    2000
    +  put_ bh (ImpDeclSpec mod as pkg_qual qual implicit _dloc isboot isstage) = do
    
    1999 2001
         put_ bh mod
    
    2000 2002
         put_ bh as
    
    2001 2003
         put_ bh pkg_qual
    
    2002 2004
         put_ bh qual
    
    2005
    +    put_ bh implicit
    
    2003 2006
         put_ bh isboot
    
    2004 2007
         put_ bh (fromEnum isstage)
    
    2005 2008
     
    
    ... ... @@ -2008,9 +2011,10 @@ instance Binary ImpDeclSpec where
    2008 2011
         as <- get bh
    
    2009 2012
         pkg_qual <- get bh
    
    2010 2013
         qual <- get bh
    
    2014
    +    implicit <- get bh
    
    2011 2015
         isboot <- get bh
    
    2012 2016
         isstage <- toEnum <$> get bh
    
    2013
    -    return (ImpDeclSpec mod as pkg_qual qual noSrcSpan isboot isstage)
    
    2017
    +    return (ImpDeclSpec mod as pkg_qual qual implicit noSrcSpan isboot isstage)
    
    2014 2018
     
    
    2015 2019
     -- | Import Item Specification
    
    2016 2020
     --
    

  • testsuite/tests/plugins/Makefile
    ... ... @@ -234,3 +234,7 @@ test-late-plugin:
    234 234
     	ContainsLateBinding=$$(echo $$SHOW_IFACE | grep -o 222222) ; \
    
    235 235
     	echo "$$ContainsLateBinding" ; \
    
    236 236
     	[ "$$ContainsEarlyBinding" = "111111" ] && [ "$$ContainLateBinding" = "" ]
    
    237
    +
    
    238
    +.PHONY: T21730
    
    239
    +T21730:
    
    240
    +	"$(TEST_HC)" $(TEST_HC_OPTS) $(ghcPluginWayFlags) -v0 T21730.hs -package-db T21730-plugin/pkg.T21730-plugin/local.package.conf

  • testsuite/tests/plugins/T21730-plugin/Makefile
    1
    +TOP=../../..
    
    2
    +include $(TOP)/mk/boilerplate.mk
    
    3
    +include $(TOP)/mk/test.mk
    
    4
    +
    
    5
    +clean.%:
    
    6
    +	rm -rf pkg.$*
    
    7
    +
    
    8
    +HERE := $(abspath .)
    
    9
    +$(eval $(call canonicalise,HERE))
    
    10
    +
    
    11
    +package.%:
    
    12
    +	$(MAKE) -s --no-print-directory clean.$*
    
    13
    +	mkdir pkg.$*
    
    14
    +	"$(TEST_HC)" -outputdir pkg.$* --make -v0 -o pkg.$*/setup Setup.hs
    
    15
    +	"$(GHC_PKG)" init pkg.$*/local.package.conf
    
    16
    +	pkg.$*/setup configure --distdir pkg.$*/dist -v0 $(CABAL_PLUGIN_BUILD) --prefix="$(HERE)/pkg.$*/install" --with-compiler="$(TEST_HC)" --with-hc-pkg="$(GHC_PKG)" --package-db=pkg.$*/local.package.conf $(if $(findstring YES,$(HAVE_PROFILING)), --enable-library-profiling)
    
    17
    +	pkg.$*/setup build     --distdir pkg.$*/dist -v0
    
    18
    +	pkg.$*/setup install   --distdir pkg.$*/dist -v0

  • testsuite/tests/plugins/T21730-plugin/Setup.hs
    1
    +import Distribution.Simple
    
    2
    +main = defaultMain

  • testsuite/tests/plugins/T21730-plugin/T21730-plugin.cabal
    1
    +Name:           T21730-plugin
    
    2
    +Version:        0.1
    
    3
    +Synopsis:       For testing
    
    4
    +Cabal-Version:  >= 1.2
    
    5
    +Build-Type:     Simple
    
    6
    +
    
    7
    +Library
    
    8
    +    Build-Depends: base, ghc
    
    9
    +    Exposed-Modules: T21730_Plugin

  • testsuite/tests/plugins/T21730-plugin/T21730_Plugin.hs
    1
    +module T21730_Plugin (plugin) where
    
    2
    +
    
    3
    +import GHC.Hs
    
    4
    +import GHC.Plugins
    
    5
    +import GHC.Types.Fixity
    
    6
    +import qualified GHC.Types.Name.Occurrence as NameSpace
    
    7
    +
    
    8
    +plugin :: Plugin
    
    9
    +plugin = defaultPlugin
    
    10
    +  { parsedResultAction = \_ _ parsedResult ->
    
    11
    +      pure $ parsedResult
    
    12
    +        { parsedResultModule =
    
    13
    +            let modl = parsedResultModule parsedResult
    
    14
    +            in modl { hpm_module = update <$> hpm_module modl }
    
    15
    +        }
    
    16
    +  }
    
    17
    +  where
    
    18
    +    update modl =
    
    19
    +      modl
    
    20
    +        { hsmodImports = newImport : hsmodImports modl
    
    21
    +        , hsmodDecls = newDecl : hsmodDecls modl
    
    22
    +        }
    
    23
    +
    
    24
    +    newImport = genLoc $ simpleImportDecl $ mkModuleName "Data.Char"
    
    25
    +    newFuncName = genLoc $ mkRdrName "toLower2"
    
    26
    +    newDecl =
    
    27
    +      genLoc . ValD NoExtField $
    
    28
    +        mkFunBind (Generated OtherExpansion SkipPmc) newFuncName $
    
    29
    +          [ mkSimpleMatch
    
    30
    +              (mkPrefixFunRhs newFuncName noAnn)
    
    31
    +              (L noAnn [])
    
    32
    +              (nlHsVar (mkRdrName "toLower"))
    
    33
    +          ]
    
    34
    +
    
    35
    +genLoc :: (NoAnn ann) => e -> GenLocated (EpAnn ann) e
    
    36
    +genLoc = L (noAnnSrcSpan generatedSrcSpan)
    
    37
    +
    
    38
    +mkRdrName :: String -> RdrName
    
    39
    +mkRdrName = mkRdrUnqual . mkOccName NameSpace.varName

  • testsuite/tests/plugins/T21730.hs
    1
    +{-# OPTIONS_GHC -fplugin T21730_Plugin #-}
    
    2
    +{-# OPTIONS_GHC -Werror=unused-imports #-}
    
    3
    +
    
    4
    +main :: IO ()
    
    5
    +main = return ()

  • testsuite/tests/plugins/all.T
    ... ... @@ -376,3 +376,9 @@ test('test-late-plugin',
    376 376
          [extra_files(['late-plugin/LatePlugin.hs']), ignore_stdout],
    
    377 377
          makefile_test,
    
    378 378
          [])
    
    379
    +
    
    380
    +test('T21730',
    
    381
    +     [extra_files(['T21730-plugin/']),
    
    382
    +      pre_cmd('$MAKE -s --no-print-directory -C T21730-plugin package.T21730-plugin TOP={top}')
    
    383
    +      ],
    
    384
    +     makefile_test, [])