crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.22k stars 1.61k forks source link

`Module validation failed` with proc in recursive def #14596

Open ASnow opened 1 month ago

ASnow commented 1 month ago

Bug Report

Module validation failed: Function return type does not match operand type of return inst!
  ret ptr %2, !dbg !152
 %"->" = type { ptr, ptr }Function return type does not match operand type of return inst!
  ret ptr %52, !dbg !173
 %"->" = type { ptr, ptr }Function return type does not match operand type of return inst!
  ret ptr %1, !dbg !210
 %"->" = type { ptr, ptr }Function return type does not match operand type of return inst!
  ret ptr %19, !dbg !244
 %"->" = type { ptr, ptr }Function return type does not match operand type of return inst!
  ret ptr %0, !dbg !263
 %"->" = type { ptr, ptr } (Exception)
  from /crystal/src/llvm/module.cr:73:9 in 'codegen'
  from /crystal/src/compiler/crystal/compiler.cr:202:16 in 'compile:combine_rpath'
  from /crystal/src/compiler/crystal/compiler.cr:195:56 in 'compile:combine_rpath'
  from /crystal/src/compiler/crystal/command.cr:239:5 in 'run'
  from /crystal/src/compiler/crystal.cr:11:1 in '__crystal_main'
  from /crystal/src/crystal/main.cr:129:5 in 'main'
  from src/env/__libc_start_main.c:95:2 in 'libc_start_main_stage2'
Error: you've found a bug in the Crystal compiler. Please open an issue, including source code that will allow us to reproduce the bug: https://github.com/crystal-lang/crystal/issues

In docker image https://hub.docker.com/layers/crystallang/crystal/1.12-alpine/images/sha256-297e82182800ff101755a2a26de747d6654eae3b487eb108aeac3299f181408d?context=explore

Blacksmoke16 commented 1 month ago

Can you share a minimal reproducible example that causes this error?

ASnow commented 1 month ago

Sorry. It took times to find exception point.

alias DslReplaceCondsFn = -> Bool
alias DslReplaceConds = Array(DslReplaceConds) | DslReplaceCondsFn

  def _replace_map(cond : DslReplaceConds) : DslReplaceCondsFn
    if cond.is_a?(Array)
      cond_fns = cond.map { |x| _replace_map(x) }
      ->() { (cond_fns.all? { |fn| fn.call }) } # problem is here if write  "? true : false " problem wil be fixed
  else
  ->() { false }
   end
 end

_replace_map([-> () { true }, -> () { false }])
HertzDevil commented 1 month ago

You could also write -> : Bool { cond_fns.all? { |fn| fn.call } }, since it looks like the compiler had issues inferring that return type.

Reduction: (note that recursive types are not needed here, only a recursive def)

class Foo
  @x = uninitialized -> Bool
end

def foo(cond) : -> Bool
  if cond.is_a?(Foo)
    -> { foo(cond.@x).call }
  else
    cond
  end
end

foo(Foo.new)