[project @ 2002-07-29 12:22:37 by simonpj]
[ghc-hetmet.git] / ghc / compiler / rename / RnEnv.lhs
index c2c6762..3e8dd5b 100644 (file)
@@ -8,13 +8,14 @@ module RnEnv where            -- Export everything
 
 #include "HsVersions.h"
 
-import {-# SOURCE #-} RnHiFiles
+import {-# SOURCE #-} RnHiFiles( loadInterface )
 
 import FlattenInfo      ( namesNeededForFlattening )
 import HsSyn
-import RdrHsSyn                ( RdrNameIE, RdrNameHsType, extractHsTyRdrTyVars )
+import RnHsSyn         ( RenamedFixitySig )
+import RdrHsSyn                ( RdrNameIE, RdrNameHsType, RdrNameFixitySig, extractHsTyRdrTyVars )
 import RdrName         ( RdrName, rdrNameModule, rdrNameOcc, isQual, isUnqual, isOrig,
-                         mkRdrUnqual, mkRdrQual, 
+                         mkRdrUnqual, mkRdrQual, setRdrNameOcc,
                          lookupRdrEnv, foldRdrEnv, rdrEnvToList, elemRdrEnv,
                          unqualifyRdrName
                        )
@@ -24,24 +25,25 @@ import HscTypes             ( Provenance(..), pprNameProvenance, hasBetterProv,
                          AvailInfo, Avails, GenAvailInfo(..), NameSupply(..), 
                          ModIface(..), GhciMode(..),
                          Deprecations(..), lookupDeprec,
-                         extendLocalRdrEnv
+                         extendLocalRdrEnv, lookupFixity
                        )
 import RnMonad
 import Name            ( Name, 
                          getSrcLoc, nameIsLocalOrFrom,
                          mkInternalName, mkExternalName,
                          mkIPName, nameOccName, nameModule_maybe,
-                         setNameModuleAndLoc
+                         setNameModuleAndLoc, nameModule
                        )
 import NameEnv
 import NameSet
-import OccName         ( OccName, occNameUserString, occNameFlavour )
+import OccName         ( OccName, occNameUserString, occNameFlavour, 
+                         isDataSymOcc, setOccNameSpace, tcName )
 import Module          ( ModuleName, moduleName, mkVanillaModule, 
                          mkSysModuleNameFS, moduleNameFS, WhereFrom(..) )
 import PrelNames       ( mkUnboundName, 
                          derivingOccurrences,
                          mAIN_Name, main_RDR_Unqual,
-                         runMainName, intTyConName, 
+                         runIOName, intTyConName, 
                          boolTyConName, funTyConName,
                          unpackCStringName, unpackCStringFoldrName, unpackCStringUtf8Name,
                          eqStringName, printName, 
@@ -54,10 +56,11 @@ import SrcLoc               ( SrcLoc, noSrcLoc )
 import Outputable
 import ListSetOps      ( removeDups, equivClasses )
 import Util            ( sortLt )
-import BasicTypes      ( mapIPName )
+import BasicTypes      ( mapIPName, defaultFixity )
 import List            ( nub )
 import UniqFM          ( lookupWithDefaultUFM )
 import Maybe           ( mapMaybe )
+import Maybes          ( orElse, catMaybes )
 import CmdLineOpts
 import FastString      ( FastString )
 \end{code}
@@ -211,7 +214,16 @@ lookupTopBndrRn rdr_name
        -- The parser reads the special syntax and returns an Orig RdrName
        -- But the global_env contains only Qual RdrNames, so we won't
        -- find it there; instead just get the name via the Orig route
-  = lookupOrigName rdr_name
+       --
+  =    -- This is a binding site for the name, so check first that it 
+       -- the current module is the correct one; otherwise GHC can get
+       -- very confused indeed.  This test rejects code like
+       --      data T = (,) Int Int
+       -- unless we are in GHC.Tup
+    getModuleRn                                `thenRn` \ mod -> 
+    checkRn (moduleName mod == rdrNameModule rdr_name)
+           (badOrigBinding rdr_name)   `thenRn_`
+    lookupOrigName rdr_name
 
   | otherwise
   = getModeRn  `thenRn` \ mode ->
@@ -231,9 +243,9 @@ lookupTopBndrRn rdr_name
        Just name -> returnRn name
        Nothing   -> failWithRn (mkUnboundName rdr_name)
                                (unknownNameErr rdr_name)
-  where
-    lookup_local mod global_env rdr_name
-      = case lookupRdrEnv global_env rdr_name of
+
+lookup_local mod global_env rdr_name
+  = case lookupRdrEnv global_env rdr_name of
          Nothing   -> Nothing
          Just gres -> case [n | GRE n _ _ <- gres, nameIsLocalOrFrom mod n] of
                         []     -> Nothing
@@ -411,6 +423,104 @@ lookupSysBinder rdr_name
 
 %*********************************************************
 %*                                                     *
+\subsection{Looking up fixities}
+%*                                                     *
+%*********************************************************
+
+lookupFixity is a bit strange.  
+
+* Nested local fixity decls are put in the local fixity env, which we
+  find with getFixtyEnv
+
+* Imported fixities are found in the HIT or PIT
+
+* Top-level fixity decls in this module may be for Names that are
+    either  Global        (constructors, class operations)
+    or             Local/Exported (everything else)
+  (See notes with RnNames.getLocalDeclBinders for why we have this split.)
+  We put them all in the local fixity environment
+
+\begin{code}
+lookupFixityRn :: Name -> RnMS Fixity
+lookupFixityRn name
+  = getModuleRn                                `thenRn` \ this_mod ->
+    if nameIsLocalOrFrom this_mod name
+    then       -- It's defined in this module
+       getFixityEnv                    `thenRn` \ local_fix_env ->
+       returnRn (lookupLocalFixity local_fix_env name)
+
+    else       -- It's imported
+      -- For imported names, we have to get their fixities by doing a
+      -- loadHomeInterface, and consulting the Ifaces that comes back
+      -- from that, because the interface file for the Name might not
+      -- have been loaded yet.  Why not?  Suppose you import module A,
+      -- which exports a function 'f', thus;
+      --        module CurrentModule where
+      --         import A( f )
+      --       module A( f ) where
+      --         import B( f )
+      -- Then B isn't loaded right away (after all, it's possible that
+      -- nothing from B will be used).  When we come across a use of
+      -- 'f', we need to know its fixity, and it's then, and only
+      -- then, that we load B.hi.  That is what's happening here.
+        loadInterface doc name_mod ImportBySystem      `thenRn` \ iface ->
+       returnRn (lookupFixity (mi_fixities iface) name)
+  where
+    doc      = ptext SLIT("Checking fixity for") <+> ppr name
+    name_mod = moduleName (nameModule name)
+
+--------------------------------
+lookupLocalFixity :: LocalFixityEnv -> Name -> Fixity
+lookupLocalFixity env name
+  = case lookupNameEnv env name of 
+       Just (FixitySig _ fix _) -> fix
+       Nothing                  -> defaultFixity
+
+extendNestedFixityEnv :: [(Name, RenamedFixitySig)] -> RnMS a -> RnMS a
+-- Used for nested fixity decls
+-- No need to worry about type constructors here,
+-- Should check for duplicates but we don't
+extendNestedFixityEnv fixes enclosed_scope
+  = getFixityEnv       `thenRn` \ fix_env ->
+    let
+       new_fix_env = extendNameEnvList fix_env fixes
+    in
+    setFixityEnv new_fix_env enclosed_scope
+
+mkTopFixityEnv :: GlobalRdrEnv -> [RdrNameFixitySig] -> RnMG LocalFixityEnv
+mkTopFixityEnv gbl_env fix_sigs 
+  = getModuleRn                                `thenRn` \ mod -> 
+    let
+               -- GHC extension: look up both the tycon and data con 
+               -- for con-like things
+               -- If neither are in scope, report an error; otherwise
+               -- add both to the fixity env
+       go fix_env (FixitySig rdr_name fixity loc)
+         = case catMaybes (map (lookup_local mod gbl_env) rdr_names) of
+                 [] -> pushSrcLocRn loc                        $
+                       addErrRn (unknownNameErr rdr_name)      `thenRn_`
+                       returnRn fix_env
+                 ns -> foldlRn add fix_env ns
+
+         where
+           add fix_env name 
+             = case lookupNameEnv fix_env name of
+                 Just (FixitySig _ _ loc') -> addErrRn (dupFixityDecl rdr_name loc loc')       `thenRn_`
+                                              returnRn fix_env
+                 Nothing -> returnRn (extendNameEnv fix_env name (FixitySig name fixity loc))
+           
+           rdr_names | isDataSymOcc occ = [rdr_name, rdr_name_tc]
+                     | otherwise            = [rdr_name]
+
+           occ         = rdrNameOcc rdr_name
+           rdr_name_tc = setRdrNameOcc rdr_name (setOccNameSpace occ tcName)
+    in
+    foldlRn go emptyLocalFixityEnv fix_sigs
+\end{code}
+
+
+%*********************************************************
+%*                                                     *
 \subsection{Implicit free vars and sugar names}
 %*                                                     *
 %*********************************************************
@@ -457,7 +567,7 @@ ubiquitousNames
 checkMain ghci_mode mod_name gbl_env
        -- LOOKUP main IF WE'RE IN MODULE Main
        -- The main point of this is to drag in the declaration for 'main',
-       -- its in another module, and for the Prelude function 'runMain',
+       -- its in another module, and for the Prelude function 'runIO',
        -- so that the type checker will find them
        --
        -- We have to return the main_name separately, because it's a
@@ -472,7 +582,7 @@ checkMain ghci_mode mod_name gbl_env
 
   | otherwise
   = lookupSrcName gbl_env main_RDR_Unqual      `thenRn` \ main_name ->
-    returnRn (Just main_name, unitFV main_name, unitFV runMainName)
+    returnRn (Just main_name, unitFV main_name, unitFV runIOName)
 
   where
     complain_no_main | ghci_mode == Interactive = addWarnRn noMainMsg
@@ -499,28 +609,38 @@ At the moment this just happens for
   * fromInteger, fromRational on literals (in expressions and patterns)
   * negate (in expressions)
   * minus  (arising from n+k patterns)
+  * "do" notation
 
 We store the relevant Name in the HsSyn tree, in 
   * HsIntegral/HsFractional    
   * NegApp
   * NPlusKPatIn
+  * HsDo
 respectively.  Initially, we just store the "standard" name (PrelNames.fromIntegralName,
 fromRationalName etc), but the renamer changes this to the appropriate user
 name if Opt_NoImplicitPrelude is on.  That is what lookupSyntaxName does.
 
+We treat the orignal (standard) names as free-vars too, because the type checker
+checks the type of the user thing against the type of the standard thing.
+
 \begin{code}
-lookupSyntaxName :: Name       -- The standard name
-                -> RnMS Name   -- Possibly a non-standard name
+lookupSyntaxName :: Name                       -- The standard name
+                -> RnMS (Name, FreeVars)       -- Possibly a non-standard name
 lookupSyntaxName std_name
-  = doptRn Opt_NoImplicitPrelude       `thenRn` \ no_prelude -> 
+  = getModeRn                          `thenRn` \ mode ->
+    case mode of {
+       InterfaceMode -> returnRn (std_name, unitFV std_name) ;
+                               -- Happens for 'derived' code
+                               -- where we don't want to rebind
+       other ->
+
+    doptRn Opt_NoImplicitPrelude       `thenRn` \ no_prelude -> 
     if not no_prelude then
-       returnRn std_name       -- Normal case
+       returnRn (std_name, unitFV std_name)    -- Normal case
     else
-    let
-       rdr_name = mkRdrUnqual (nameOccName std_name)
        -- Get the similarly named thing from the local environment
-    in
-    lookupOccRn rdr_name
+    lookupOccRn (mkRdrUnqual (nameOccName std_name)) `thenRn` \ usr_name ->
+    returnRn (usr_name, mkFVs [usr_name, std_name]) }
 \end{code}
 
 
@@ -1050,6 +1170,10 @@ unknownNameErr name
   where
     flavour = occNameFlavour (rdrNameOcc name)
 
+badOrigBinding name
+  = ptext SLIT("Illegal binding of built-in syntax:") <+> ppr (rdrNameOcc name)
+       -- The rdrNameOcc is because we don't want to print Prelude.(,)
+
 qualNameErr descriptor (name,loc)
   = pushSrcLocRn loc $
     addErrRn (vcat [ ptext SLIT("Invalid use of qualified name") <+> quotes (ppr name),
@@ -1067,5 +1191,10 @@ warnDeprec name txt
     addWarnRn (sep [ text (occNameFlavour (nameOccName name)) <+> 
                     quotes (ppr name) <+> text "is deprecated:", 
                     nest 4 (ppr txt) ])
+
+dupFixityDecl rdr_name loc1 loc2
+  = vcat [ptext SLIT("Multiple fixity declarations for") <+> quotes (ppr rdr_name),
+         ptext SLIT("at ") <+> ppr loc1,
+         ptext SLIT("and") <+> ppr loc2]
 \end{code}