wasmtime/runtime/component/
matching.rs1use crate::component::func::HostFunc;
2use crate::component::linker::{Definition, Strings};
3use crate::component::ResourceType;
4use crate::runtime::vm::component::ComponentInstance;
5use crate::types::matching;
6use crate::Module;
7use crate::{prelude::*, Engine};
8use alloc::sync::Arc;
9use core::any::Any;
10use wasmtime_environ::component::{
11 ComponentTypes, NameMap, ResourceIndex, TypeComponentInstance, TypeDef, TypeFuncIndex,
12 TypeModule, TypeResourceTableIndex,
13};
14use wasmtime_environ::PrimaryMap;
15
16pub struct TypeChecker<'a> {
17 pub engine: &'a Engine,
18 pub types: &'a Arc<ComponentTypes>,
19 pub strings: &'a Strings,
20 pub imported_resources: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
21}
22
23#[derive(Copy, Clone)]
24#[doc(hidden)]
25pub struct InstanceType<'a> {
26 pub types: &'a Arc<ComponentTypes>,
27 pub resources: &'a Arc<PrimaryMap<ResourceIndex, ResourceType>>,
28}
29
30impl TypeChecker<'_> {
31 pub(crate) fn definition(
32 &mut self,
33 expected: &TypeDef,
34 actual: Option<&Definition>,
35 ) -> Result<()> {
36 match *expected {
37 TypeDef::Module(t) => match actual {
38 Some(Definition::Module(actual)) => self.module(&self.types[t], actual),
39 Some(actual) => bail!("expected module found {}", actual.desc()),
40 None => bail!("module implementation is missing"),
41 },
42 TypeDef::ComponentInstance(t) => match actual {
43 Some(Definition::Instance(actual)) => self.instance(&self.types[t], Some(actual)),
44 None => self.instance(&self.types[t], None),
45 Some(actual) => bail!("expected instance found {}", actual.desc()),
46 },
47 TypeDef::ComponentFunc(t) => match actual {
48 Some(Definition::Func(actual)) => self.func(t, actual),
49 Some(actual) => bail!("expected function found {}", actual.desc()),
50 None => bail!("function implementation is missing"),
51 },
52 TypeDef::Component(_) => match actual {
53 Some(actual) => bail!("expected component found {}", actual.desc()),
54 None => bail!("component implementation is missing"),
55 },
56 TypeDef::Interface(_) => match actual {
57 Some(actual) => bail!("expected type found {}", actual.desc()),
58 None => bail!("type implementation is missing"),
59 },
60
61 TypeDef::Resource(i) => {
62 let i = self.types[i].ty;
63 let actual = match actual {
64 Some(Definition::Resource(actual, _dtor)) => actual,
65
66 None if self.imported_resources.get(i).is_some() => return Ok(()),
73
74 Some(actual) => bail!("expected resource found {}", actual.desc()),
75 None => bail!("resource implementation is missing"),
76 };
77
78 match self.imported_resources.get(i) {
79 None => {
90 let resources = Arc::get_mut(&mut self.imported_resources).unwrap();
91 let id = resources.push(*actual);
92 assert_eq!(id, i);
93 }
94
95 Some(expected) => {
102 if expected != actual {
103 bail!("mismatched resource types");
104 }
105 }
106 }
107 Ok(())
108 }
109
110 TypeDef::CoreFunc(_) => unreachable!(),
112 }
113 }
114
115 fn module(&self, expected: &TypeModule, actual: &Module) -> Result<()> {
116 let actual = actual.env_module();
117
118 for (name, expected) in expected.exports.iter() {
120 let idx = actual
121 .exports
122 .get(name)
123 .ok_or_else(|| anyhow!("module export `{name}` not defined"))?;
124 let actual = actual.type_of(*idx);
125 matching::entity_ty(self.engine, expected, &actual)
126 .with_context(|| format!("module export `{name}` has the wrong type"))?;
127 }
128
129 for (module, name, actual) in actual.imports() {
134 let expected = expected
136 .imports
137 .get(&(module.to_string(), name.to_string()))
138 .ok_or_else(|| anyhow!("module import `{module}::{name}` not defined"))?;
139 matching::entity_ty(self.engine, &actual, expected)
140 .with_context(|| format!("module import `{module}::{name}` has the wrong type"))?;
141 }
142 Ok(())
143 }
144
145 fn instance(
146 &mut self,
147 expected: &TypeComponentInstance,
148 actual: Option<&NameMap<usize, Definition>>,
149 ) -> Result<()> {
150 for (name, expected) in expected.exports.iter() {
154 if let TypeDef::Interface(_) = expected {
158 continue;
159 }
160 let actual = actual.and_then(|map| map.get(name, self.strings));
161 self.definition(expected, actual)
162 .with_context(|| format!("instance export `{name}` has the wrong type"))?;
163 }
164 Ok(())
165 }
166
167 fn func(&self, expected: TypeFuncIndex, actual: &HostFunc) -> Result<()> {
168 let instance_type = InstanceType {
169 types: self.types,
170 resources: &self.imported_resources,
171 };
172 actual.typecheck(expected, &instance_type)
173 }
174}
175
176impl Definition {
177 fn desc(&self) -> &'static str {
178 match self {
179 Definition::Module(_) => "module",
180 Definition::Func(_) => "func",
181 Definition::Instance(_) => "instance",
182 Definition::Resource(..) => "resource",
183 }
184 }
185}
186
187impl<'a> InstanceType<'a> {
188 pub fn new(instance: &'a ComponentInstance) -> InstanceType<'a> {
189 InstanceType {
190 types: instance.component_types(),
191 resources: downcast_arc_ref(instance.resource_types()),
192 }
193 }
194
195 pub fn resource_type(&self, index: TypeResourceTableIndex) -> ResourceType {
196 let index = self.types[index].ty;
197 self.resources
198 .get(index)
199 .copied()
200 .unwrap_or_else(|| ResourceType::uninstantiated(&self.types, index))
201 }
202}
203
204fn downcast_arc_ref<T: 'static>(arc: &Arc<dyn Any + Send + Sync>) -> &Arc<T> {
210 let _ = arc.downcast_ref::<T>();
212
213 unsafe { &*(arc as *const Arc<dyn Any + Send + Sync> as *const Arc<T>) }
216}