Repository: veryl-lang/veryl (Rust)

Issue:
Can't use fixed type as argument for generic type parameter
Veryl will report `mismatch type` error for a fixed type specified as argument for generic type parameter.

```systemverilog
module Top {
  function FuncA::<T: type>() -> T {
    return 0 as T;
  }

  function FuncB() -> u32 {
    return FuncA::<u32>();
  }
}
```

![Image](https://github.com/user-attachments/assets/bc2d4f87-d4cc-4b1d-9e73-df4658bd78dc)


Discussion:

Patch:
diff --git a/crates/analyzer/src/handlers/check_type.rs b/crates/analyzer/src/handlers/check_type.rs
index 7748f2c2f..df4275104 100644
--- a/crates/analyzer/src/handlers/check_type.rs
+++ b/crates/analyzer/src/handlers/check_type.rs
@@ -5,7 +5,7 @@ use crate::attribute_table;
 use crate::namespace::Namespace;
 use crate::namespace_table;
 use crate::symbol::{GenericBoundKind, ProtoBound, Symbol, SymbolId, SymbolKind};
-use crate::symbol_path::{GenericSymbolPath, SymbolPathNamespace};
+use crate::symbol_path::{GenericSymbolPath, GenericSymbolPathKind, SymbolPathNamespace};
 use crate::symbol_table;
 use veryl_parser::resource_table;
 use veryl_parser::veryl_grammar_trait::*;
@@ -45,6 +45,22 @@ impl Handler for CheckType {
     }
 }
 
+fn check_generic_type_arg(arg: &GenericSymbolPath, namespace: &Namespace) -> Option<String> {
+    if matches!(arg.kind, GenericSymbolPathKind::FixedType) {
+        return None;
+    } else if arg.is_resolvable() {
+        let Ok(symbol) = symbol_table::resolve((&arg.generic_path(), namespace)) else {
+            return Some("not found".to_string());
+        };
+
+        if symbol.found.is_variable_type() {
+            return None;
+        }
+    }
+
+    Some(arg.kind.to_string())
+}
+
 fn resolve_inst_generic_arg_type(arg: &GenericSymbolPath, namespace: &Namespace) -> Option<Symbol> {
     if !arg.is_resolvable() {
         return None;
@@ -349,23 +365,13 @@ impl VerylGrammarTrait for CheckType {
                             let bound = &param.1.bound;
                             match bound {
                                 GenericBoundKind::Type => {
-                                    let is_type = if arg.is_resolvable() {
-                                        if let Ok(symbol) =
-                                            symbol_table::resolve((&arg.generic_path(), &namespace))
-                                        {
-                                            symbol.found.is_variable_type()
-                                        } else {
-                                            false
-                                        }
-                                    } else {
-                                        false
-                                    };
-
-                                    if !is_type {
+                                    if let Some(error_kind) =
+                                        check_generic_type_arg(arg, &namespace)
+                                    {
                                         self.errors.push(AnalyzerError::mismatch_type(
-                                            &symbol.found.token.to_string(),
-                                            "enum or union or struct",
-                                            &symbol.found.kind.to_kind_name(),
+                                            &arg.to_string(),
+                                            "enum, union, struct, typedef or fixed type",
+                                            &error_kind,
                                             &arg.range,
                                         ));
                                     }


Test patch:
diff --git a/crates/analyzer/src/tests.rs b/crates/analyzer/src/tests.rs
index 66f07d9e7..636c22f3e 100644
--- a/crates/analyzer/src/tests.rs
+++ b/crates/analyzer/src/tests.rs
@@ -2727,6 +2727,21 @@ fn mismatch_type() {
 
     let errors = analyze(code);
     assert!(errors.is_empty());
+
+    let code = r#"
+    module ModuleA {
+        function FuncA::<T: type>() -> T {
+            return 0 as T;
+        }
+
+        function FuncB() -> u32 {
+            return FuncA::<u32>();
+        }
+    }
+    "#;
+
+    let errors = analyze(code);
+    assert!(errors.is_empty());
 }
 
 #[test]