Skip to content

Commit f285e79

Browse files
RaoulHCraehik
authored andcommitted
Fix assignment to array in a struct
This is a redo of a patch by @aburzillo to correctly analyse the type of data references, due to the changes to fortran-src types and the new `SemanticType`. Given the plan to eventually use the information from this stage in the type checker this partial support for structures will need to be extended.
1 parent 97afb65 commit f285e79

File tree

2 files changed

+92
-16
lines changed

2 files changed

+92
-16
lines changed

src/Language/Fortran/Analysis/Types.hs

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import Prelude hiding (lookup, EQ, LT, GT)
2121
import Data.Map (insert)
2222
import qualified Data.Map as M
2323
import Data.Maybe (maybeToList)
24-
import Data.List (find)
24+
import Data.List (find, foldl')
2525
import Control.Monad.State.Strict
2626
import Data.Generics.Uniplate.Data
2727
import Data.Data
@@ -41,13 +41,18 @@ type TypeEnv = M.Map Name IDType
4141
-- | Information about a detected type error.
4242
type TypeError = (String, SrcSpan)
4343

44+
-- | Mapping of structures to field types
45+
type StructTypeEnv = M.Map Name StructMemberTypeEnv
46+
type StructMemberTypeEnv = M.Map Name IDType
47+
4448
--------------------------------------------------
4549

4650
-- Monad for type inference work
4751
type Infer a = State InferState a
4852
data InferState = InferState { langVersion :: FortranVersion
4953
, intrinsics :: IntrinsicsTable
5054
, environ :: TypeEnv
55+
, structs :: StructTypeEnv
5156
, entryPoints :: M.Map Name (Name, Maybe Name)
5257
, typeErrors :: [TypeError] }
5358
deriving Show
@@ -167,41 +172,68 @@ dimDeclarator ddAList = [ (lb, ub) | DimensionDeclarator _ _ lbExp ubExp <- aStr
167172
, let ub = do ExpValue _ _ (ValInteger i) <- ubExp
168173
return $ read i ]
169174

170-
statement :: Data a => InferFunc (Statement (Analysis a))
171-
172-
statement (StDeclaration _ stmtSs ts@(TypeSpec _ _ _ _) mAttrAList declAList)
175+
-- | Auxiliary function for getting semantic and construct type of a declaration.
176+
-- Used in standard declarations and structures
177+
handleDeclaration :: Data a => TypeEnv -> SrcSpan -> TypeSpec (Analysis a)
178+
-> Maybe (AList Attribute (Analysis a))
179+
-> AList Declarator (Analysis a)
180+
-> Infer [(Name, SemType, ConstructType)]
181+
handleDeclaration env stmtSs ts mAttrAList declAList
173182
| mAttrs <- maybe [] aStrip mAttrAList
174183
, attrDim <- find isAttrDimension mAttrs
175184
, isParam <- any isAttrParameter mAttrs
176185
, isExtrn <- any isAttrExternal mAttrs
177-
, decls <- aStrip declAList = do
178-
env <- gets environ
186+
, decls <- aStrip declAList =
179187
let cType n | isExtrn = CTExternal
180188
| Just (AttrDimension _ _ ddAList) <- attrDim = CTArray (dimDeclarator ddAList)
181189
| isParam = CTParameter
182190
| Just (IDType _ (Just ct)) <- M.lookup n env
183191
, ct /= CTIntrinsic = ct
184192
| otherwise = CTVariable
185-
forM_ decls $ \ decl -> case decl of
186-
DeclArray _ declSs v ddAList mLenExpr _ -> do
187-
let ct = CTArray $ dimDeclarator ddAList
193+
handler rs = \case
194+
DeclArray _ declSs v ddAList mLenExpr _ -> do
188195
st <- deriveSemTypeFromDeclaration stmtSs declSs ts mLenExpr
189-
recordType st ct (varName v)
190-
DeclVariable _ declSs v mLenExpr _ -> do
196+
pure $ (varName v, st, CTArray $ dimDeclarator ddAList) : rs
197+
DeclVariable _ declSs v mLenExpr _ -> do
191198
st <- deriveSemTypeFromDeclaration stmtSs declSs ts mLenExpr
192-
recordType st (cType n) n where n = varName v
199+
let n = varName v
200+
pure $ (n, st, cType n) : rs
201+
in foldM handler [] decls
202+
203+
handleStructureItem :: Data a => StructMemberTypeEnv -> StructureItem (Analysis a) -> Infer StructMemberTypeEnv
204+
handleStructureItem mt (StructFields _ src ts mAttrAList declAList) = do
205+
env <- gets environ
206+
ds <- handleDeclaration env src ts mAttrAList declAList
207+
pure $ foldl' (\m (n, s, c) -> M.insert n (IDType (Just s) (Just c)) m) mt ds
208+
-- TODO: These should eventually be implemented
209+
handleStructureItem mt StructUnion{} = pure mt
210+
handleStructureItem mt StructStructure{} = pure mt
211+
212+
-- | Create a structure env from the list of fields and add it to the InferState
213+
handleStructure ::Data a => Maybe String -> AList StructureItem (Analysis a) -> Infer ()
214+
handleStructure mName itemAList = do
215+
case mName of
216+
Just n -> do
217+
structEnv <- foldM handleStructureItem M.empty (aStrip itemAList)
218+
recordStruct structEnv n
219+
Nothing -> pure ()
220+
221+
statement :: Data a => InferFunc (Statement (Analysis a))
193222

223+
statement (StDeclaration _ stmtSs ts mAttrAList declAList) = do
224+
env <- gets environ
225+
decls <- handleDeclaration env stmtSs ts mAttrAList declAList
226+
forM_ decls $ \(n, b, c) -> recordType b c n
194227
statement (StExternal _ _ varAList) = do
195228
let vars = aStrip varAList
196229
mapM_ (recordCType CTExternal . varName) vars
197230
statement (StExpressionAssign _ _ (ExpSubscript _ _ v ixAList) _)
198231
-- | any (not . isIxSingle) (aStrip ixAList) = recordCType CTArray (varName v) -- it's an array (or a string?) FIXME
199232
| all isIxSingle (aStrip ixAList) = do
200-
let n = varName v
201-
mIDType <- getRecordedType n
233+
mIDType <- getExprRecordedType v
202234
case mIDType of
203235
Just (IDType _ (Just CTArray{})) -> return () -- do nothing, it's already known to be an array
204-
_ -> recordCType CTFunction n -- assume it's a function statement
236+
_ -> recordCType CTFunction (varName v) -- assume it's a function statement
205237

206238
-- FIXME: if StFunctions can only be identified after types analysis
207239
-- is complete and disambiguation is performed, then how do we get
@@ -216,6 +248,8 @@ statement (StDimension _ _ declAList) = do
216248
DeclArray _ _ v ddAList _ _ -> recordCType (CTArray $ dimDeclarator ddAList) (varName v)
217249
_ -> return ()
218250

251+
statement (StStructure _ _ mName itemAList) = handleStructure mName itemAList
252+
219253
statement _ = return ()
220254

221255
annotateExpression :: Data a => Expression (Analysis a) -> Infer (Expression (Analysis a))
@@ -417,7 +451,7 @@ isNumericType = \case
417451
-- Monadic helper combinators.
418452

419453
inferState0 :: FortranVersion -> InferState
420-
inferState0 v = InferState { environ = M.empty, entryPoints = M.empty, langVersion = v
454+
inferState0 v = InferState { environ = M.empty, structs = M.empty, entryPoints = M.empty, langVersion = v
421455
, intrinsics = getVersionIntrinsics v, typeErrors = [] }
422456
runInfer :: FortranVersion -> TypeEnv -> State InferState a -> (a, InferState)
423457
runInfer v env = flip runState ((inferState0 v) { environ = env })
@@ -432,6 +466,9 @@ emptyType = IDType Nothing Nothing
432466
recordType :: SemType -> ConstructType -> Name -> Infer ()
433467
recordType st ct n = modify $ \ s -> s { environ = insert n (IDType (Just st) (Just ct)) (environ s) }
434468

469+
recordStruct :: StructMemberTypeEnv -> Name -> Infer ()
470+
recordStruct mt n = modify $ \s -> s { structs = insert n mt (structs s) }
471+
435472
-- Record the type (maybe) of the given name.
436473
recordMType :: Maybe SemType -> Maybe ConstructType -> Name -> Infer ()
437474
recordMType st ct n = modify $ \ s -> s { environ = insert n (IDType st ct) (environ s) }
@@ -452,6 +489,24 @@ recordEntryPoint fn en mRetName = modify $ \ s -> s { entryPoints = M.insert en
452489
getRecordedType :: Name -> Infer (Maybe IDType)
453490
getRecordedType n = gets (M.lookup n . environ)
454491

492+
getExprRecordedType :: Data a => Expression (Analysis a) -> Infer (Maybe IDType)
493+
getExprRecordedType e@(ExpValue _ _ (ValVariable _)) = getRecordedType $ varName e
494+
getExprRecordedType (ExpSubscript _ _ base _) = do
495+
mTy <- getExprRecordedType base
496+
case mTy of
497+
Just (IDType semTy (Just CTArray{})) -> pure . Just $ IDType semTy (Just CTVariable)
498+
_ -> pure Nothing
499+
getExprRecordedType (ExpDataRef _ _ base ref) = do
500+
mTy <- getExprRecordedType base
501+
case mTy of
502+
Just (IDType (Just (TCustom n)) _) -> do
503+
mStructEnv <- gets (M.lookup n . structs)
504+
case mStructEnv of
505+
Nothing -> pure Nothing
506+
Just env -> pure $ M.lookup (varName ref) env
507+
x -> pure x
508+
getExprRecordedType _ = pure Nothing
509+
455510
-- Set the idType annotation
456511
setIDType :: Annotated f => IDType -> f (Analysis a) -> f (Analysis a)
457512
setIDType ty x

test/Language/Fortran/Analysis/TypesSpec.hs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Language.Fortran.Analysis
1212
import Language.Fortran.Analysis.Types
1313
import Language.Fortran.Analysis.SemanticTypes
1414
import Language.Fortran.Analysis.Renaming
15+
import qualified Language.Fortran.Parser.Fortran77 as F77
1516
import qualified Language.Fortran.Parser.Fortran90 as F90
1617
import Language.Fortran.ParserMonad
1718
import qualified Data.ByteString.Char8 as B
@@ -22,6 +23,9 @@ inferTable = underRenaming (snd . analyseTypes)
2223
typedProgramFile :: Data a => ProgramFile a -> ProgramFile (Analysis a)
2324
typedProgramFile = fst . analyseTypes . analyseRenames . initAnalysis
2425

26+
legacy77Parser :: String -> String -> ProgramFile A0
27+
legacy77Parser src file = fromParseResultUnsafe $ F77.legacy77Parser (B.pack src) file
28+
2529
fortran90Parser :: String -> String -> ProgramFile A0
2630
fortran90Parser src file = fromParseResultUnsafe $ F90.fortran90Parser (B.pack src) file
2731

@@ -148,6 +152,11 @@ spec = do
148152
(Just (CTArray [(Nothing, Just 20)])))]
149153
`shouldNotSatisfy` null
150154

155+
describe "Structure arrays" $ do
156+
it "can handle typing assignments to arrays within structs" $ do
157+
let mapping = inferTable structArray
158+
mapping ! "s" `shouldBe` IDType (Just $ TCustom "strut") (Just CTVariable)
159+
151160
ex1 :: ProgramFile ()
152161
ex1 = ProgramFile mi77 [ ex1pu1 ]
153162
ex1pu1 :: ProgramUnit ()
@@ -306,6 +315,18 @@ teststrings1 = resetSrcSpan . flip fortran90Parser "" $ unlines [
306315
, "end program teststrings"
307316
]
308317

318+
structArray :: ProgramFile A0
319+
structArray = resetSrcSpan . flip legacy77Parser "" $ unlines [
320+
" subroutine totes"
321+
, " structure /strut/"
322+
, " integer*4 arr(10)"
323+
, " end structure"
324+
, " record /strut/ s"
325+
, " s.arr(7) = 345"
326+
, " print *, 'eyo'"
327+
, " end subroutine totes"
328+
]
329+
309330
-- Local variables:
310331
-- mode: haskell
311332
-- haskell-program-name: "cabal repl test-suite:spec"

0 commit comments

Comments
 (0)