wasmtime/runtime/component/
matching.rs1use crate::Module;
2use crate::component::ResourceType;
3use crate::component::func::HostFunc;
4use crate::component::linker::Definition;
5use crate::component::types::{FutureType, StreamType};
6use crate::runtime::vm::component::ComponentInstance;
7use crate::types::matching;
8use crate::{Engine, prelude::*};
9use alloc::sync::Arc;
10use wasmtime_environ::component::{
11 ComponentTypes, NameMap, ResourceIndex, TypeComponentInstance, TypeDef, TypeFuncIndex,
12 TypeFutureTableIndex, TypeModule, TypeResourceTable, TypeResourceTableIndex,
13 TypeStreamTableIndex,
14};
15use wasmtime_environ::prelude::TryPrimaryMap;
16use wasmtime_environ::{Atom, StringPool};
17
18pub struct TypeChecker<'a> {
19 pub engine: &'a Engine,
20 pub types: &'a Arc<ComponentTypes>,
21 pub strings: &'a StringPool,
22 pub imported_resources: Arc<TryPrimaryMap<ResourceIndex, ResourceType>>,
23}
24
25#[derive(Copy, Clone)]
26#[doc(hidden)]
27pub struct InstanceType<'a> {
28 pub types: &'a Arc<ComponentTypes>,
29 pub resources: Option<&'a Arc<TryPrimaryMap<ResourceIndex, ResourceType>>>,
36}
37
38impl TypeChecker<'_> {
39 pub(crate) fn definition(
40 &mut self,
41 expected: &TypeDef,
42 actual: Option<&Definition>,
43 ) -> Result<()> {
44 match *expected {
45 TypeDef::Module(t) => match actual {
46 Some(Definition::Module(actual)) => self.module(&self.types[t], actual),
47 Some(actual) => bail!("expected module found {}", actual.desc()),
48 None => bail!("module implementation is missing"),
49 },
50 TypeDef::ComponentInstance(t) => match actual {
51 Some(Definition::Instance(actual)) => self.instance(&self.types[t], Some(actual)),
52 None => self.instance(&self.types[t], None),
53 Some(actual) => bail!("expected instance found {}", actual.desc()),
54 },
55 TypeDef::ComponentFunc(t) => match actual {
56 Some(Definition::Func(actual)) => self.func(t, actual),
57 Some(actual) => bail!("expected function found {}", actual.desc()),
58 None => bail!("function implementation is missing"),
59 },
60 TypeDef::Component(_) => match actual {
61 Some(actual) => bail!("expected component found {}", actual.desc()),
62 None => bail!("component implementation is missing"),
63 },
64 TypeDef::Interface(_) => match actual {
65 Some(actual) => bail!("expected type found {}", actual.desc()),
66 None => bail!("type implementation is missing"),
67 },
68
69 TypeDef::Resource(i) => {
70 let i = self.types[i].unwrap_concrete_ty();
71 let actual = match actual {
72 Some(Definition::Resource(actual, _dtor)) => actual,
73
74 None if self.imported_resources.get(i).is_some() => return Ok(()),
81
82 Some(actual) => bail!("expected resource found {}", actual.desc()),
83 None => bail!("resource implementation is missing"),
84 };
85
86 match self.imported_resources.get(i) {
87 None => {
98 let resources = Arc::get_mut(&mut self.imported_resources).unwrap();
99 let id = resources.push(*actual)?;
100 assert_eq!(id, i);
101 }
102
103 Some(expected) => {
110 if expected != actual {
111 bail!("mismatched resource types");
112 }
113 }
114 }
115 Ok(())
116 }
117
118 TypeDef::CoreFunc(_) => unreachable!(),
120 }
121 }
122
123 fn module(&self, expected: &TypeModule, actual: &Module) -> Result<()> {
124 let actual = actual.env_module();
125
126 for (name, expected) in expected.exports.iter() {
128 let idx = actual
129 .strings
130 .get_atom(name)
131 .and_then(|atom| actual.exports.get(&atom))
132 .ok_or_else(|| format_err!("module export `{name}` not defined"))?;
133 let actual = actual.type_of(*idx);
134 matching::entity_ty(self.engine, expected, &actual)
135 .with_context(|| format!("module export `{name}` has the wrong type"))?;
136 }
137
138 for (module, name, actual) in actual.imports() {
143 let expected = expected
145 .imports
146 .get(&(module.to_string(), name.to_string()))
147 .ok_or_else(|| format_err!("module import `{module}::{name}` not defined"))?;
148 matching::entity_ty(self.engine, &actual, expected)
149 .with_context(|| format!("module import `{module}::{name}` has the wrong type"))?;
150 }
151 Ok(())
152 }
153
154 fn instance(
155 &mut self,
156 expected: &TypeComponentInstance,
157 actual: Option<&NameMap<Atom, Definition>>,
158 ) -> Result<()> {
159 for (name, expected) in expected.exports.iter() {
163 if let TypeDef::Interface(_) = expected {
167 continue;
168 }
169 let actual = actual.and_then(|actual| actual.get(name, self.strings));
170 self.definition(expected, actual)
171 .with_context(|| format!("instance export `{name}` has the wrong type"))?;
172 }
173 Ok(())
174 }
175
176 fn func(&self, expected: TypeFuncIndex, actual: &HostFunc) -> Result<()> {
177 let instance_type = InstanceType {
178 types: self.types,
179 resources: Some(&self.imported_resources),
180 };
181 actual.typecheck(expected, &instance_type)
182 }
183}
184
185impl Definition {
186 fn desc(&self) -> &'static str {
187 match self {
188 Definition::Module(_) => "module",
189 Definition::Func(_) => "func",
190 Definition::Instance(_) => "instance",
191 Definition::Resource(..) => "resource",
192 }
193 }
194}
195
196impl<'a> InstanceType<'a> {
197 pub fn new(instance: &'a ComponentInstance) -> InstanceType<'a> {
198 InstanceType {
199 types: instance.component().types(),
200 resources: Some(instance.resource_types()),
201 }
202 }
203
204 pub fn resource_type(&self, index: TypeResourceTableIndex) -> ResourceType {
205 match self.types[index] {
206 TypeResourceTable::Concrete { ty, .. } => self
207 .resources
208 .map(|t| t[ty])
209 .unwrap_or_else(|| ResourceType::uninstantiated(&self.types, ty)),
210 TypeResourceTable::Abstract(ty) => ResourceType::abstract_(&self.types, ty),
211 }
212 }
213
214 pub fn future_type(&self, index: TypeFutureTableIndex) -> FutureType {
215 FutureType::from(self.types[index].ty, self)
216 }
217
218 pub fn stream_type(&self, index: TypeStreamTableIndex) -> StreamType {
219 StreamType::from(self.types[index].ty, self)
220 }
221}