roc icon indicating copy to clipboard operation
roc copied to clipboard

Error in alias analysis

Open Anton-4 opened this issue 2 years ago • 17 comments

This only happens with the basic-cli args example, not with the similar args example in the roc repo.

RUST_BACKTRACE=1 ./target/release/roc build --linker=legacy /home/username/gitrepos/basic-cli/examples/args.roc
🔨 Rebuilding platform...
thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x1b\x00\x00\x00\x12\x00\x00\x00\xbe\xd12$b\x077\x15"), definition of value binding ValueId(59): could not find func in module ModName("UserApp") with name FuncName("\x8c\x00\x00\x00\x12\x00\x00\x00\x1d\xca$\xf15\xe8\xd8\x98")', crates/compiler/gen_llvm/src/llvm/build.rs:5094:19
stack backtrace:
   0: rust_begin_unwind
             at /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/std/src/panicking.rs:575:5
   1: core::panicking::panic_fmt
             at /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/panicking.rs:64:14
   2: roc_gen_llvm::llvm::build::build_procedures_help
   3: roc_gen_llvm::llvm::build::build_procedures
   4: roc_build::program::gen_from_mono_module
   5: roc_build::program::build_loaded_file
   6: roc_build::program::build_file
   7: roc_cli::build
   8: roc::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

This error was introduced by PR #5576

@ayazhafiz would it help if I try to minimize the args example or do you already know what's going wrong?

Anton-4 avatar Jul 28 '23 10:07 Anton-4

Yes please, minimizing would help a lot.

ayazhafiz avatar Jul 28 '23 12:07 ayazhafiz

Here is my attempt at a minimal repro, I may have found something related see comment in this example.

app "args"
    packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.4.0/DI4lqn7LIZs8ZrCDUgLK-tHHpQmxGF1ZrlevRKq5LXk.tar.br" }
    imports [
        pf.Arg, 
        pf.Task,
    ]
    provides [main] to pf

main =
    args <- Arg.list |> Task.await

    when Arg.parseFormatted parser args is
        Ok _ -> crash ""
        Err _ -> crash ""

UserCommand : [Div F64 F64, Log F64 F64]

parser : Arg.NamedParser UserCommand
parser =
    Arg.program 
        logSubCmd
        { 
            name: "args-example", 
            help: "A calculator example of the CLI platform argument parser" 
        }

logSubCmd : Arg.Parser UserCommand
logSubCmd =

    # WORKS WITH THIS
    # Arg.succeed (Log 1.0 1.0)

    # DOES NOT WORK WITH THIS
    Arg.succeed (\base -> \num -> Log (Num.toF64 base) (Num.toF64 num))
    |> Arg.withParser
        (
            Arg.i64Option {
                long: "base",
                short: "b",
                help: "base of the logarithm",
            }
        )
    |> Arg.withParser
        (
            Arg.i64Option {
                long: "num",
                help: "the number to take the logarithm of",
            }
        )

lukewilliamboswell avatar Jul 29 '23 04:07 lukewilliamboswell

Thanks @lukewilliamboswell :)

Should we try to minimize the basic-cli platform as well @ayazhafiz?

Anton-4 avatar Jul 29 '23 09:07 Anton-4

friendly ping @ayazhafiz

Should we try to minimize the basic-cli platform as well @ayazhafiz?

Anton-4 avatar Aug 01 '23 14:08 Anton-4

Yes please!

On Tue, Aug 1, 2023 at 9:57 AM Anton-4 @.***> wrote:

friendly ping @ayazhafiz https://github.com/ayazhafiz

Should we try to minimize the basic-cli platform as well @ayazhafiz https://github.com/ayazhafiz?

— Reply to this email directly, view it on GitHub https://github.com/roc-lang/roc/issues/5701#issuecomment-1660498356, or unsubscribe https://github.com/notifications/unsubscribe-auth/AE6GL6THGJRWWK2FJDCBVPTXTEKOPANCNFSM6AAAAAA23JS634 . You are receiving this because you were mentioned.Message ID: @.***>

ayazhafiz avatar Aug 01 '23 14:08 ayazhafiz

I have maximally minimized the platform and the example: args_minimal_platform.tar.gz

Code to run:

basic-cli on  main [✘!?] via ❄  impure (nix-shell-env) 
❯ ./roc_nightly/roc build examples/argsGOOD.roc
🔨 Rebuilding platform...
0 errors and 0 warnings found in 6294 ms while successfully building:

    examples/args

basic-cli on  main [✘!?] via ❄  impure (nix-shell-env) took 6s 
❯ ./roc_nightly/roc build examples/argsBROKEN.roc 
🔨 Rebuilding platform...
thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x1b\x00\x00\x00\x12\x00\x00\x00f\xf9\x128M\x96\x07G"), definition of value binding ValueId(59): could not find func in module ModName("UserApp") with name FuncName("\x8c\x00\x00\x00\x12\x00\x00\x00\t\xdaC\x18\xe3\xeb\x0e\xab")', crates/compiler/gen_llvm/src/llvm/build.rs:5123:19
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Anton-4 avatar Sep 02 '23 14:09 Anton-4

Do you have some time available to look into this issue in the coming weeks @ayazhafiz? In case it may help, Brendan also recently did some digging into a very similar issue.

Given that this issue breaks command line arguments for the basic-cli platform, it would be really valuable to have this fixed.

Anton-4 avatar Oct 20 '23 08:10 Anton-4

@Anton-4 I think the first step is a further minimization. I know you, Luke, and Brendan have looked into simplifying the reproduction and that has been super valuable, but it's unlikely we will make progress on diagnosing the issue unless we can have a minimal reproducer that is only a few functions long (or at most one module).

ayazhafiz avatar Oct 20 '23 11:10 ayazhafiz

That is, stand-alone functions with no dependency on any platform.

ayazhafiz avatar Oct 20 '23 11:10 ayazhafiz

Alright , that's good to know. I can look at further optimization once I'm done with higher priority issues, but it if anyone else can take it that would be great too :)

Anton-4 avatar Oct 20 '23 11:10 Anton-4

Another large example with a similar error. Once we've fixed the minimal case, we should check if this code is fixed too.

roc script
# this source is partially minimized, see original at https://github.com/salarii/peek/blob/e6e0b29fd5b715cb05d0bdfef2a16194f474d01d/regex.roc

app "reg"
    packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.5.0/Cufzl36_SnJ4QbOoEmiJ5dIpUxBvdB3NEySvuH82Wio.tar.br" }
    imports [pf.Stdout]
    provides [main] to pf


firstStagePatterns = [
        { tag : Dot, str : "."},
    ]


priorities =
    Dict.empty {}
    |> Dict.insert Empty -1
    |> Dict.insert Character 0
    |> Dict.insert Dot 1

emptyNode = { locked : Bool.false, children :  [], value : [] }

treeBase = 
    {cnt : 0, content : Dict.empty {} }
    |> addElement  0 emptyNode
    
createParsingRecord = \ regex, meta ->
     { regex : regex, current : regex, matched : [], result : Bool.false, missed : [], left : [] , captured : treeBase, meta : meta, strict : No } 


checkMatchingValidity = \ matchingResult ->
    when matchingResult.strict is 
        No -> Bool.true 
        Front -> List.isEmpty  matchingResult.missed
        Back -> List.isEmpty  matchingResult.left 
        Both -> (List.isEmpty  matchingResult.missed) && (List.isEmpty  matchingResult.left)



modifyLastInList = \ lst, elem ->
    List.dropLast lst 1
    |> List.append elem


getPrioToken = \ patterns ->
    if List.isEmpty patterns then
        Err NoTokens
    else
        List.walk patterns (Err Empty) (\ state, pattern -> 
            when state is 
                Err Empty ->
                    when Dict.get priorities  pattern.tag is
                        Ok _ -> Ok pattern
                        Err _ -> Err PriorityListErr 
                Ok prevPat ->  
                          
                    when Dict.get priorities prevPat.tag is
                        Ok val1 ->
                            when Dict.get priorities  pattern.tag is
                                Ok val2 ->
                                    if val2 > val1 then 
                                        Ok pattern
                                    else 
                                        state
                                Err _ -> Err PriorityListErr 
                        Err _ -> Err PriorityListErr
                Err message -> Err message 
        )

createToken = \ token, serie, capture ->
    { token :token, serie : serie, capture : capture  }

regexSeedPattern = [
    { tag : Character, tokens : [ createToken  Dot  Once Bool.false ] } ]

#  test  this, I could not figure  out  how to do this properly 
splitChainOnSeparators = \ chain, inputLst ->
    when List.first chain is 
        Ok elem ->
            when elem.token is 
                Separator -> 

                        List.walk ( splitChainOnSeparators (List.dropFirst chain 1) []) [] ( \ state, lst ->
                            List.append state lst
                        )
                        |>   List.append []
                Sequence  inChain ->

                    partialSeqResult =
                        List.walk ( splitChainOnSeparators inChain []) [] ( \ outState, frontLst ->                               
                            
                            List.walk ( splitChainOnSeparators (List.dropFirst chain 1) []) outState ( \ state, lst ->                                
                                List.append state  ( List.concat [ {elem & token : Sequence frontLst } ]  lst) 
                            )        
                        )   
          
                    when List.last partialSeqResult is
                        Ok activElem ->
                            List.dropLast partialSeqResult 1
                            |> List.walk  [] ( \ state,  lst ->
                                List.append state (List.concat inputLst lst))
                            |> List.append  activElem
                        Err _ ->
                            []
                     
                _ ->

                    partialResult =
                        List.walk ( splitChainOnSeparators (List.dropFirst chain 1) (List.append inputLst elem )) [] ( \ state, lst ->
                                List.append state lst
                        )

                    when List.last partialResult is 
                        Ok lst -> 
                            modifyLastInList partialResult  (List.concat [elem] lst)  
                        Err _ -> 
                            []
                    
        Err _ ->
            [[]]
        

    
evalRegex = \ utfLst, patterns, regex ->
    if List.isEmpty utfLst then
        Ok regex
    else
        List.walk patterns [] ( \ state, pattern ->
            out = checkMatching utfLst pattern.tokens
            if out.result == Bool.true   && List.isEmpty out.missed then
                List.append state { tag : pattern.tag, parsedResult : out } 
            else
                state 
            )
        |> getPrioToken
        |> ( \ prioToken ->
            when prioToken is
                Ok token -> evalRegex token.parsedResult.left patterns  ( List.append regex token ) 
                Err message ->  Err message  )

checkMatching = \ utfLst, reg  ->
    
    matchStr = \ utf, pattern ->
        when pattern is 
            Character val ->
                if val == utf then
                    Consume    
                else
                    NoMatch
            Dot ->
                Consume
            _ -> NoMatch
    
    matchUtf = ( \ utf, tokenMeta ->
        result = matchStr utf tokenMeta.token
        
        when result is
            Consume -> Consume tokenMeta 
            NoMatch -> NoMatch tokenMeta 
    )

    updateRegex = (\regex ->   
        List.walk  regex [] ( \ state, regItem ->
            when List.first regItem.current is 
                Ok pat ->
                    when pat.token  is
                        Sequence  chain ->
                            when pat.serie is 
                                AtLeastOne ->           
                                    changeFront = 
                                        (List.dropFirst regItem.current 1)
                                        |> List.prepend { pat & serie : ZeroOrMore }
                                        
                                    List.concat chain changeFront
                                    |> (\ updatedCurrent ->  List.append state {regItem & current : updatedCurrent} )  
                                ZeroOrMore ->

                                    List.append state {regItem & current : (List.dropFirst regItem.current 1)}  
                                    |> List.append 
                                        (List.concat chain (List.dropFirst regItem.current 1)
                                        |> (\ updatedCurrent ->  {regItem & current : updatedCurrent, meta : Active} ))
                                NTimes cnt -> 
                                    concatIter = (\ n , lst, stored ->
                                        if n == 0 then 
                                            stored
                                        else 
                                            concatIter (n-1) lst (List.concat lst stored  ))
                                    
                                    List.concat (concatIter cnt chain  [] ) (List.dropFirst regItem.current 1)
                                    |> (\ updatedCurrent ->  List.append state {regItem & current : updatedCurrent} )  
                                Once ->
                                    List.concat chain (List.dropFirst regItem.current 1)
                                    |> (\ updatedCurrent ->  List.append state {regItem & current : updatedCurrent} )  
                        _ -> List.append state regItem
                    
                Err _ -> List.append state regItem )
        )

    getFirstPat = (\  state  ->  
        if state.meta == Inactive then
            Inactive state
        else
            when List.first state.current is
                Ok pat -> 
                    Active { pattern : pat , state : state } 
                Err _ ->
                    if state.meta == Origin then
                        # BUG  in this  line
                        #getFirstPat  { state & current : state.regex } 
                        getFirstPat  { regex : state.regex, current : state.regex, matched : state.matched, result : state.result, missed : state.missed, left : state.left, captured : state.captured, meta : state.meta, strict : state.strict } 

                    else   
                        Inactive {state & meta : Inactive } 
            )


    complexSearch = 
        List.walk utfLst [createParsingRecord reg Origin]  ( \ outState, utf ->
            
            updatedStates = updateRegex outState 
            
            List.walk updatedStates [] ( \ state, processedReg ->   
                
                if processedReg.result == Bool.true then
                    List.append state { processedReg & left : List.append  processedReg.left utf} 
                else   
                    manageIteration = ( \ inProcessedReg,curState ->
                  
                        when getFirstPat inProcessedReg is
                            Inactive _patternSet ->
                                List.append curState inProcessedReg
                            Active matchThis ->
                                toUpdateState = matchThis.state  
                                if matchThis.pattern.token == CaptureOpen then
                                    tmpState = {toUpdateState & current : List.dropFirst toUpdateState.current 1}

                                    manageIteration { tmpState &  captured : (composeMatchedStructure tmpState.captured  0 CaptureOpen) }  curState
                                    
                                else if matchThis.pattern.token == CaptureClose then
                                    
                                    tmpState = {toUpdateState & current : List.dropFirst toUpdateState.current 1}    
                                    manageIteration { tmpState &   captured : composeMatchedStructure tmpState.captured  0 CaptureClose } curState
                                else
                                    
                                    updatedState = matchThis.state
                                    current = List.dropFirst  updatedState.current  1
                                    #   BUG  this  crashes 
                                    ppp = List.isEmpty current == Bool.true 
                                    
                                    updatedCapture =
                                        if matchThis.pattern.capture == Bool.true then
                                            when  changeValue updatedState.captured 0 utf  is 
                                                Ok updatedTree -> updatedTree
                                                Err _ ->  updatedState.captured
                                        else
                                            updatedState.captured
                                    
                                    when matchUtf utf  matchThis.pattern is 
                                        Consume _updatedToken ->
                                            if List.len current == 0 then
                                                List.append curState { updatedState &  matched : List.append updatedState.matched  utf, current : current, result : Bool.true, left : [], captured : updatedCapture}
                                            else
                                                List.append curState { updatedState & matched : List.append updatedState.matched  utf, current : current, left : [], captured : updatedCapture} 
                                        NoMatch _ ->
                                                
                                                # BUG second line 
                                                # updateMissed = List.concat updatedState.missed  updatedState.matched
                                               
                                                #List.append curState { updatedState &  matched : [], current : updatedState.regex, missed : List.append updateMissed utf, left : [], captured : treeBase}
                                                List.append curState { regex : updatedState.regex, current : updatedState.regex, matched : [], result : updatedState.result, missed : updatedState.missed, left : updatedState.left, captured : treeBase, meta : updatedState.meta, strict : updatedState.strict }
                                                
                                        _ -> curState  
                                )
                    manageIteration processedReg state ) 
        )
    List.walk complexSearch  (createParsingRecord reg Inactive) ( \ state, parsResult -> 
        if state.result == Bool.true then
            if (List.len parsResult.matched > List.len state.matched ) && (checkMatchingValidity state) then 
                parsResult
            else 
                state
        else 
            parsResult )
    
getRegexTokens = \ result  -> 
    when result.tag is 
        Character-> 
            when List.first result.parsedResult.matched is 
                Ok  matched  -> Ok [(createToken  ( Character matched )  Once Bool.false )]
                Err  _  -> Err "character  tag problem"
            
        _ -> Err "wrong tag"


 

regexCreationStage = \ inPatterns, ignitionPatterns ->

    regPatterns = 
        List.walk inPatterns (Ok []) ( \ state, pat->
            when state is 
                Ok patterns -> 
                    when evalRegex (Str.toUtf8  pat.str ) ignitionPatterns [] is 
                        Ok results ->
                            List.walk  results (Ok []) ( \ inState, result ->
                                when inState is 
                                    Ok patLst ->
                                        when  getRegexTokens result is 
                                            Ok tokens -> 
                                                workaround = 
                                                    List.walk  tokens [] ( \ workState, token -> 
                                                        List.append workState (createToken token.token token.serie  token.capture) )
                                                # !!!!!!!!!!! crashes  here Ok [{ tag : pat.tag, tokens : tokens }]
                                                Ok (List.concat patLst  workaround  )    

                                            Err message -> Err message 
                                    Err  message -> Err message     
                                
                            )
                            |> (\ inTokensResult ->
                                when  inTokensResult is 
                                    Ok inTokens ->  
                                        Ok ( List.append patterns { tag : pat.tag, tokens : inTokens } )
                                    Err message ->  Err message )

                        Err Empty ->  Err "Empty" 
                        Err NoTokens ->  Err "NoTokens"
                        Err PriorityListErr ->  Err "PriorityListErr"
                Err message ->  Err message )
    when regPatterns is 
        Ok patterns ->
            Ok ( List.concat  ignitionPatterns  patterns )
        Err  message  -> Err  message  
    
    
stagesCreationRegex  = \ _param -> 
    regexCreationStage firstStagePatterns regexSeedPattern
    #stage1  = regexCreationStage firstStagePatterns regexSeedPattern
    #when stage1 is 
    #    Ok stage1Pat -> 
    #        regexCreationStage secondStagePatterns stage1Pat
                
    #    Err message -> 
    #        Err message


regexCreationStage2  = \ str, patterns, currReg ->
    ( evalRegex (Str.toUtf8  str) patterns currReg )
    |> ( \ resultSet -> 
        when resultSet is
            Ok  results ->
                List.walk results (Ok { lst : [] , capture : Bool.false }) ( \ outState, result  ->
                    when outState is 
                        Err message -> Err message 
                        Ok state ->
                            modifLastInChain = (\ chainLst, token ->
                                when List.last chainLst is 
                                    Ok elem ->
                                        when elem.token is 
                                            Sequence  chain ->
                                                when List.last chain is
                                                    Ok _lastOnChain ->
                                                        when token.token is 
                                                            CaptureClose -> 
                                                                List.append chainLst token            
                                                            _ -> 
                                                                modifyLastInList chainLst (createToken (Sequence ( modifLastInChain chain token))  Once Bool.false)

                                                    Err _ ->
                                                        modifyLastInList  chainLst  (createToken (Sequence ( modifLastInChain chain token))  Once Bool.false)
                                            _ ->  
                                                List.append chainLst token                  
                                    Err _ ->
                                        List.append chainLst token
                                        
                            )
                                            
                            when  result.tag is 
                                Character ->
                                    when List.first result.parsedResult.matched is 
                                        Ok  matched  ->
                                            Ok { state &  lst : modifLastInChain state.lst  (createToken (Character matched) Once state.capture) }
                                        Err _ -> Err "parser  match problem"
                                    
                                Dot ->
                                    Ok { state &  lst : modifLastInChain state.lst (createToken Dot Once state.capture )  }
                                CaptureOpen ->
                                    
                                    openLst = 
                                        modifLastInChain state.lst (createToken CaptureOpen Once Bool.false)
                                        |> modifLastInChain  (createToken (Sequence []) Once Bool.false)
                                    Ok { lst : openLst, capture : Bool.true}
                                Digit ->
                                    Ok { state &  lst : modifLastInChain state.lst (createToken Digit Once Bool.false )  }
                                NoDigit ->
                                    Ok { state &  lst : modifLastInChain state.lst (createToken NoDigit Once Bool.false )  }
                                Alphanumeric ->
                                    limitRangToken = LimitRanges [{ left : 'A', right : 'Z' },{ left : 'a', right : 'z' },{ left : '0', right : '9' }]
                                    Ok { state &  lst : modifLastInChain state.lst (createToken limitRangToken Once Bool.false )  }
                     
                                Empty -> Err "Empty"  
                        )
                |> (\ tokenLst -> 
                    when tokenLst is 
                        Ok lstRec ->
                            Ok lstRec.lst
                        Err message -> Err message  )
                         
            Err Empty ->  Err "Empty" 
            Err NoTokens ->  Err "NoTokens"
            Err PriorityListErr ->  Err "PriorityListErr"
    )
    
    

    
#    checkMatching str reg  ->
# create  patterns  and  than  parse  string with it     

availableRegex = stagesCreationRegex [] 

# maybe at some point add some additional error handling ??


# to be replaced 


addElement = \ tree, parentId ,node -> 
    when Dict.get tree.content parentId  is 
        Ok element -> 
            updatedContent = 
                Dict.remove tree.content parentId
                |> Dict.insert parentId {element  & children : (List.append element.children tree.cnt )}
            
            { cnt : tree.cnt + 1, content : (Dict.insert updatedContent  tree.cnt node )  }          
        Err _ -> { cnt : tree.cnt + 1, content : Dict.insert tree.content  tree.cnt node }
    
    
changeElement = \ tree, id ,node -> 
    when Dict.get tree.content id  is 
        Ok _element -> 
            updatedContent = 
                Dict.remove tree.content id
                |> Dict.insert id node
            
            { tree & content : updatedContent }          
        Err _ -> { cnt : tree.cnt + 1, content : Dict.insert tree.content  tree.cnt node }


modifyActive = \ tree, headId, op ->
    when Dict.get tree.content headId  is 
        Ok head -> 
            if List.isEmpty head.children == Bool.true then
                op headId tree
            else 
                when List.last head.children is 
                    Ok nodeId ->
                        when Dict.get tree.content nodeId is 
                            Ok child ->
                                if child.locked == Bool.true then
                                    op headId tree
                                else 
                                    modifyActive tree nodeId op
                            Err _ -> Err  "internal logic error"
                    Err _ -> Err  "internal logic error"
                        
        Err _ -> Err  "wrong tree node id"


changeValue = \ tree, id, value-> 
    modify = 
        \ idValue, treeValue ->
            when Dict.get treeValue.content idValue is 
                Ok node ->
                    Ok (changeElement treeValue idValue {node & value : List.append node.value value  } )
                Err _ -> Err  "internal logic error"

    modifyActive tree id modify
                    
composeMatchedStructure = \ tree, id,tag ->
    
    addNewNode = \ idNew, treeNew -> Ok (addElement treeNew idNew emptyNode)
    
    lockNode = 
        \ idLock, treeLocked ->
            when Dict.get treeLocked.content idLock is 
                Ok node ->
                    Ok (changeElement treeLocked idLock {node & locked : Bool.true } )
                Err _ -> Err  "internal logic error"
    result = 
        when tag is 
            CaptureOpen -> 
                if Dict.isEmpty tree.content == Bool.false then 
                    modifyActive tree id addNewNode 
                else
                    Err  "internal logic error"
            CaptureClose ->
                modifyActive tree id lockNode
    when result is
        Ok newTree -> newTree
        Err _  -> tree
          

parseStr = \ str, pattern -> 
    when availableRegex is 
        Ok stage1Pat -> 
            tokensFromUserInputResult = regexCreationStage2 pattern stage1Pat  []
            
            when tokensFromUserInputResult is 
                Ok tokensFromUserInput ->
                    independentChainlst = splitChainOnSeparators tokensFromUserInput []
                    # for now get longest maybe??
                    
                    Ok (List.walk independentChainlst (createParsingRecord [] Inactive)  ( \ state, regexParser ->  
                        parsResult = checkMatching (Str.toUtf8  str ) regexParser    
                        if state.result then
                            if List.len parsResult.matched > List.len state.matched  then 
                                parsResult
                            else 
                                state
                            else 
                                parsResult ))
                Err message -> 
                    Err (Str.concat "You screwed up something, or not supported construction, or internal bug \n"  message )

        Err message -> 
            Err  (Str.concat "This is internal regex error not your fault\n"  message )


main =
    pp =  parseStr  "sss"   "a"    
    
    Stdout.line "outStr"
    

Anton-4 avatar Nov 14 '23 14:11 Anton-4

Very compact example, still depends on the basic-cli platform though...

mainLoop = \x ->
    _ <- Stdout.line "hello \(Num.toStr x)" |> Task.await
    if x == 3 then
        Task.ok {}
    else
        mainLoop (x + 1)

main =
    mainLoop 0

Anton-4 avatar Dec 18 '23 17:12 Anton-4

I encountered a similar recursive task problem when I played with roc-w4 platform:

Point : {
    x : I32,
    y : I32,
}

randPoint : Point -> Task Point []
randPoint = \maxPoint ->
    x <- W4.randBetween { start: 0, before: maxPoint.x } |> Task.await
    y <- W4.randBetween { start: 0, before: maxPoint.y } |> Task.await

    Task.ok {
        x,
        y,
    }

anotherRandPoint : Point, Point -> Task Point []
anotherRandPoint = \maxPoint, point ->
    nextPoint <- randPoint maxPoint |> Task.await

    if nextPoint != point then
        Task.ok nextPoint
    else
        anotherRandPoint maxPoint point

and then used it like this:

    start <- randPoint { x: 20, y: 20 } |> Task.await
    end <- anotherRandPoint { x: 20, y: 20 } start |> Task.await

I get this error during compilation with roc build ...

thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x12\x00\x00\x00\x02\x00\x00\x00_\xcbk6\xad\xefW\x99"), definition of value binding ValueId(3): could not find func in module ModName("UserApp") with name FuncName("\x19\x00\x00\x00\x04\x00\x00\x00_\xcbk6\xad\xefW\x99")', crates/compiler/gen_llvm/src/llvm/build.rs:5743:19
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Anyway, I planned to implement a simple prng to avoid touching the platform. Just reporting another example of the problem

kdziamura avatar Jan 21 '24 13:01 kdziamura

I ran into this error before doing some parsing. Given it was in a package without a platform involved, I tried minimalizing the error. This is the best I got, split over two modules:

Main.roc

interface Main
    exposes []
    imports [Helper]

expect
    _ = Helper.f (loop {})
    1 == 1

loop = \{} ->
    Helper.g \_ ->
        if Bool.true then
            loop {}
        else
            \_ -> {}

Helper.roc

interface Helper
    exposes [f, g]
    imports []

f : ({} -> {}) -> {}
f = \_ -> {}

g : ({} -> ({} -> {})) -> ({} -> {})
g = \fn -> \_ -> (fn {}) {}

I get the error when running roc test Main.roc.

thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x11\x00\x00\x00\x00\x00\x00\x00z\xfd\x94\xa6\xfbT\x849"), definition of value binding ValueId(4): could not find func in module ModName("UserApp") with name FuncName("\x12\x00\x00\x00\x01\x00\x00\x00W\xb5\xe6M\xdd\xd3\xb7\xe4")', crates/compiler/gen_llvm/src/llvm/build.rs:5779:19
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Interestingly, if I move either f or g from Helper.roc to Main.roc, then the error disappears. My guess is that's maybe why we haven't managed reproductions without a platform before: it's not the platform that was relevant, but crossing a module boundary. @Anton-4's mainLoop example also has two calls to another module: Task.await and Task.ok.

Sorry for the messy types of f and g. If I try simplify them further the error disappears.

jwoudenberg avatar Mar 24 '24 18:03 jwoudenberg

Nice @jwoudenberg! Thanks for this compact reproduction :)

Anton-4 avatar Mar 25 '24 10:03 Anton-4

Here's a single file reproduction based on an error I encountered while developing Weaver:

app [main] {
    pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
}

import pf.Stdout
import pf.Task exposing [Task]

First : {}
Second : First {}

main =
    testFunc {}

testFunc : Second -> Task {} [StdoutErr Stdout.Err]
testFunc = \{} ->
    Stdout.line "abc"
$ roc appname-module-error.roc
thread 'main' panicked at crates/compiler/gen_llvm/src/llvm/build.rs:5764:19:
Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\'\x00\x00\x00,\x00\x00\x00x\xdd\x1f\x9d\x83PkI"), definition of value binding ValueId(7): could not find func in module ModName("UserApp") with name FuncName("\'\x00\x00\x00/\x00\x00\x00\xa1\xca\xcb\x7fz\xd0&\xd1")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The theory that a single layout is used for two different but identical types makes sense here.

smores56 avatar May 12 '24 20:05 smores56