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 .exports
123 .get(name)
124 .ok_or_else(|| anyhow!("module export `{name}` not defined"))?;
125 let actual = actual.type_of(*idx);
126 matching::entity_ty(self.engine, expected, &actual)
127 .with_context(|| format!("module export `{name}` has the wrong type"))?;
128 }
129
130 for (module, name, actual) in actual.imports() {
135 let expected = expected
137 .imports
138 .get(&(module.to_string(), name.to_string()))
139 .ok_or_else(|| anyhow!("module import `{module}::{name}` not defined"))?;
140 matching::entity_ty(self.engine, &actual, expected)
141 .with_context(|| format!("module import `{module}::{name}` has the wrong type"))?;
142 }
143 Ok(())
144 }
145
146 fn instance(
147 &mut self,
148 expected: &TypeComponentInstance,
149 actual: Option<&NameMap<usize, Definition>>,
150 ) -> Result<()> {
151 for (name, expected) in expected.exports.iter() {
155 if let TypeDef::Interface(_) = expected {
159 continue;
160 }
161 let actual = actual.and_then(|map| map.get(name, self.strings));
162 self.definition(expected, actual)
163 .with_context(|| format!("instance export `{name}` has the wrong type"))?;
164 }
165 Ok(())
166 }
167
168 fn func(&self, expected: TypeFuncIndex, actual: &HostFunc) -> Result<()> {
169 let instance_type = InstanceType {
170 types: self.types,
171 resources: &self.imported_resources,
172 };
173 actual.typecheck(expected, &instance_type)
174 }
175}
176
177impl Definition {
178 fn desc(&self) -> &'static str {
179 match self {
180 Definition::Module(_) => "module",
181 Definition::Func(_) => "func",
182 Definition::Instance(_) => "instance",
183 Definition::Resource(..) => "resource",
184 }
185 }
186}
187
188impl<'a> InstanceType<'a> {
189 pub fn new(instance: &'a ComponentInstance) -> InstanceType<'a> {
190 InstanceType {
191 types: instance.component().types(),
192 resources: instance.resource_types(),
193 }
194 }
195
196 pub fn resource_type(&self, index: TypeResourceTableIndex) -> ResourceType {
197 match self.types[index] {
198 TypeResourceTable::Concrete { ty, .. } => self
199 .resources
200 .get(ty)
201 .copied()
202 .unwrap_or_else(|| ResourceType::uninstantiated(&self.types, ty)),
203 TypeResourceTable::Abstract(ty) => ResourceType::abstract_(&self.types, ty),
204 }
205 }
206
207 pub fn future_type(&self, index: TypeFutureTableIndex) -> FutureType {
208 FutureType::from(self.types[index].ty, self)
209 }
210
211 pub fn stream_type(&self, index: TypeStreamTableIndex) -> StreamType {
212 StreamType::from(self.types[index].ty, self)
213 }
214}