@@ -9,6 +9,7 @@ use super::context::NativeContext;
99use crate :: {
1010 interner:: { InternedIdentifier , InternedModuleId } ,
1111 native:: { NativeStatus , VMInternalError } ,
12+ types:: InternedTypeList ,
1213} ;
1314use shared_dsa:: UnorderedMap ;
1415use thiserror:: Error ;
@@ -18,11 +19,27 @@ use thiserror::Error;
1819#[ repr( transparent) ]
1920pub struct NativeIdx ( pub u32 ) ;
2021
21- /// Fully-qualified native function name — used as keys in [`NativeRegistry`].
22- #[ derive( Clone , PartialEq , Eq , Hash ) ]
23- pub struct NativeName {
24- pub module : InternedModuleId ,
25- pub function : InternedIdentifier ,
22+ /// Key under which a native is registered in a [`NativeRegistry`].
23+ ///
24+ /// A native is either a template that serves every instantiation, or a body
25+ /// specialized to one concrete instantiation. The two variants let
26+ /// type-agnostic natives register once while type-sensitive natives register a
27+ /// separate body per concrete type. Resolution tries the monomorphic key first
28+ /// and falls back to the polymorphic one (see [`NativeRegistry::resolve`]).
29+ #[ derive( Clone , Copy , PartialEq , Eq , Hash ) ]
30+ pub enum NativeName {
31+ /// One implementation for all instantiations.
32+ Polymorphic {
33+ module : InternedModuleId ,
34+ function : InternedIdentifier ,
35+ } ,
36+ /// Implementation specialized to one concrete instantiation, matched only
37+ /// when the call's type arguments equal `ty_args`.
38+ Monomorphic {
39+ module : InternedModuleId ,
40+ function : InternedIdentifier ,
41+ ty_args : InternedTypeList ,
42+ } ,
2643}
2744
2845/// Describes a family of [`NativeContext`] types indexed by a lifetime.
@@ -48,17 +65,28 @@ pub type NativeFunction<F> = Box<
4865 + Sync ,
4966> ;
5067
51- /// Resolves a fully-qualified native name to its [`NativeIdx`].
68+ /// Resolves a native call to its [`NativeIdx`] from the callee's qualified name
69+ /// and the call's concrete type arguments.
5270pub trait NativeResolver {
53- fn resolve ( & self , name : & NativeName ) -> Option < NativeIdx > ;
71+ fn resolve (
72+ & self ,
73+ module : InternedModuleId ,
74+ function : InternedIdentifier ,
75+ ty_args : InternedTypeList ,
76+ ) -> Option < NativeIdx > ;
5477}
5578
5679/// A [`NativeResolver`] that resolves nothing -- useful for tests and simulations that
5780/// don't have any natives.
5881pub struct NoNatives ;
5982
6083impl NativeResolver for NoNatives {
61- fn resolve ( & self , _name : & NativeName ) -> Option < NativeIdx > {
84+ fn resolve (
85+ & self ,
86+ _module : InternedModuleId ,
87+ _function : InternedIdentifier ,
88+ _ty_args : InternedTypeList ,
89+ ) -> Option < NativeIdx > {
6290 None
6391 }
6492}
@@ -139,7 +167,19 @@ impl<F: NativeContextFamily> Default for NativeRegistry<F> {
139167}
140168
141169impl < F : NativeContextFamily > NativeResolver for NativeRegistry < F > {
142- fn resolve ( & self , name : & NativeName ) -> Option < NativeIdx > {
143- self . lookup_by_name ( name)
170+ /// Resolves the monomorphic registration for `ty_args` if one exists,
171+ /// otherwise falls back to a polymorphic (template) registration.
172+ fn resolve (
173+ & self ,
174+ module : InternedModuleId ,
175+ function : InternedIdentifier ,
176+ ty_args : InternedTypeList ,
177+ ) -> Option < NativeIdx > {
178+ self . lookup_by_name ( & NativeName :: Monomorphic {
179+ module,
180+ function,
181+ ty_args,
182+ } )
183+ . or_else ( || self . lookup_by_name ( & NativeName :: Polymorphic { module, function } ) )
144184 }
145185}
0 commit comments