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