odin-lang / Odin

Odin Programming Language
https://odin-lang.org
BSD 3-Clause "New" or "Revised" License
6.13k stars 551 forks source link

LLVM ERROR: Broken module found / Duplicate integer as switch case #3864

Closed iErik closed 2 days ago

iErik commented 3 days ago

Context

Odin build instructions in Nix:

{ lib
, fetchFromGitHub
, llvmPackages_17
, makeBinaryWrapper
, libiconv
, which
}:

let
  llvmPackages = llvmPackages_17;
  inherit (llvmPackages) stdenv;
in stdenv.mkDerivation rec {
  pname = "odin";
  version = "dev-2024-06";

  src = fetchFromGitHub {
    owner = "odin-lang";
    repo = "Odin";
    rev = version;
    hash = "sha256-JGTC+Gi5mkHQHvd5CmEzrhi1muzWf1rUN4f5FT5K5vc=";
  };

  nativeBuildInputs = [
    makeBinaryWrapper which
  ];

  buildInputs = [ ] ;

  LLVM_CONFIG = "${llvmPackages.llvm.dev}/bin/llvm-config";

  postPatch = ''
    substituteInPlace build_odin.sh \
        --replace-fail '-framework System' '-lSystem'
    patchShebangs build_odin.sh
  '';

  dontConfigure = true;

  buildFlags = [
    "release"
  ];

  installPhase = ''
    runHook preInstall

    mkdir -p $out/bin
    cp odin $out/bin/odin

    mkdir -p $out/share
    cp -r base $out/share/base
    cp -r core $out/share/core
    cp -r vendor $out/share/vendor

    wrapProgram $out/bin/odin \
      --prefix PATH : ${lib.makeBinPath (with llvmPackages; [
        bintools
        llvm
        clang
        lld
      ])} \
      --set-default ODIN_ROOT $out/share

    runHook postInstall
  '';

  postBuild = lib.optionalString stdenv.isLinux ''
    make -C vendor/stb/src
    make -C vendor/cgltf/src
  '';

  meta = with lib; {
    description = "A fast, concise, readable, pragmatic and open sourced programming language";
    mainProgram = "odin";
    homepage = "https://odin-lang.org/";
    license = licenses.bsd3;
    maintainers = with maintainers; [ luc65r astavie znaniye ];
    platforms = platforms.x86_64 ++ [ "aarch64-darwin" ];
  };
}

Expected Behavior

The following code should cast the variable listener.handler from ListenerProc (union) to MouseButtonHandler (#type proc)

onMouseButton :: proc (
  window: Window,
  button, action, mod: c.int
) {
  scene := cast(^Scene) glfw.GetWindowUserPointer(window)

  for &listener in scene.listeners {
    if type_of(listener.handler) == MouseButtonHandler {
      listener.handler.(MouseButtonHandler)(
        scene, listener.dataPtr, window,
        button, action, mod)
    }
  }
}
Listener :: struct {
  dataPtr: rawptr,
  handler: ListenerProc
}

ListenerProc :: union {
  MouseMoveHandler,
  MouseButtonHandler,
  MouseEnterHandler,
  KeyEventHandler,
  CharEventHandler,
  ScrollHandler,
  FramebufferSizeHandler
}

MouseMoveHandler :: #type proc (
  scene: ^Scene,
  dataPtr: rawptr,
  win: Window,
  xPos, yPos: f64)

MouseButtonHandler :: #type proc (
  scene: ^Scene,
  dataPtr: rawptr,
  win: Window,
  button: MouseButton,
  action: ButtonAction,
  mods: c.int)

MouseEnterHandler :: #type proc (
  scene: ^Scene,
  dataPtr: rawptr,
  win: Window,
  entered: bool)

KeyEventHandler :: #type proc (
  scene: ^Scene,
  dataPtr: rawptr,
  win: Window,
  key, scancode, action, mods: c.int)

CharEventHandler :: #type proc (
  scene: ^Scene,
  dataPtr: rawptr,
  win: Window,
  codepoint: rune)

ScrollHandler :: #type proc (
  scene: ^Scene,
  dataPtr: rawptr,
  win: Window,
  xOffset, yOffset: f64)

FramebufferSizeHandler :: #type proc (
  scene: ^Scene,
  dataPtr: rawptr,
  win: Window,
  width, height: c.int)

Current Behavior

Compiler gives me the following error when I try to run the code with odin run:

Duplicate integer as switch case
  switch i64 %4, label %bfalse [
    i64 0, label %bcase
    i64 1, label %bcase1
    i64 2, label %bcase2
    i64 3, label %bcase3
    i64 4, label %bcase4
    i64 5, label %bcase5
    i64 1, label %bcase6
    i64 7, label %bcase7
  ]
i64 1
LLVM ERROR: Broken module found, compilation aborted!

This happens whenever I try to cast a variable of type ListenerProc to any type within the union. I found out that this happens because two #type procs inside the ListenerProc union have the same function signature:

ScrollHandler :: #type proc (
  scene: ^Scene,
  dataPtr: rawptr,
  win: Window,
  xOffset, yOffset: f64)

And

MouseMoveHandler :: #type proc (
  scene: ^Scene,
  dataPtr: rawptr,
  win: Window,
  xPos, yPos: f64)

The code works as intended if either of these proc types are omitted in the ListenerProc union. The compiler understands both of them to be the same despite being distinct type definitions, and when both are present within the same union type it thinks that one of the union values is duplicated