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