neo_solidity/solidity/validate/contract/
library.rs

1fn validate_library(metadata: &ContractMetadata, diagnostics: &mut Vec<Diagnostic>) {
2    if !metadata.is_library {
3        return;
4    }
5
6    // Built-in devpack libraries (Runtime, Storage, Syscalls, NativeCalls, Neo, abi)
7    // use external stubs that are lowered to syscalls during IR generation.
8    // Skip user-facing library validation for these intrinsic libraries.
9    if matches!(
10        metadata.name.as_str(),
11        "Runtime" | "Storage" | "Syscalls" | "NativeCalls" | "Neo" | "abi"
12    ) {
13        return;
14    }
15
16    // Libraries cannot have state variables (constants are allowed).
17    for state in &metadata.state_variables {
18        if !state.is_constant {
19            diagnostics.push(
20                Diagnostic::error(format!(
21                    "library '{}' cannot have state variable '{}'; \
22                     libraries are stateless and cannot hold mutable storage",
23                    metadata.name,
24                    state.name.as_deref().unwrap_or("<unnamed>"),
25                ))
26                .with_suggestion(
27                    "move the state variable into a contract, or declare it as 'constant'",
28                ),
29            );
30        }
31    }
32
33    // Libraries cannot have constructors.
34    for method in &metadata.methods {
35        if matches!(method.kind, FunctionKind::Constructor) {
36            diagnostics.push(
37                Diagnostic::error(format!(
38                    "library '{}' cannot have a constructor; \
39                     libraries are not deployable and cannot be initialized",
40                    metadata.name,
41                ))
42                .with_suggestion("remove the constructor from the library"),
43            );
44        }
45    }
46
47    // Library functions: external/public are not supported on NeoVM.
48    for method in &metadata.methods {
49        if !matches!(method.kind, FunctionKind::Regular) {
50            continue;
51        }
52        match method.visibility {
53            VisibilityKind::External => {
54                diagnostics.push(
55                    Diagnostic::error(format!(
56                        "library '{}' function '{}' is declared `external`; \
57                         external library functions are not supported on NeoVM \
58                         because libraries cannot be deployed as standalone contracts",
59                        metadata.name, method.name,
60                    ))
61                    .with_suggestion(
62                        "use `internal` or `private` visibility; library functions \
63                         are inlined into the calling contract",
64                    ),
65                );
66            }
67            VisibilityKind::Public => {
68                diagnostics.push(
69                    Diagnostic::warning(format!(
70                        "library '{}' function '{}' is declared `public`; \
71                         on NeoVM, library functions are inlined into the calling \
72                         contract and `public` visibility has no effect",
73                        metadata.name, method.name,
74                    ))
75                    .with_code("W120")
76                    .with_suggestion(
77                        "use `internal` or `pure` visibility for library functions",
78                    ),
79                );
80            }
81            _ => {}
82        }
83    }
84}