diff --git a/Cargo.lock b/Cargo.lock index 055006c8021..a303d279809 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,6 +95,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.19" @@ -2322,7 +2333,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" +dependencies = [ + "ahash 0.8.2", ] [[package]] @@ -4528,6 +4548,7 @@ dependencies = [ "dirs 3.0.2", "either", "fuel-vm", + "hashbrown 0.13.1", "hex", "im", "itertools", diff --git a/forc-pkg/src/manifest.rs b/forc-pkg/src/manifest.rs index 4dce718e653..71c5f86b669 100644 --- a/forc-pkg/src/manifest.rs +++ b/forc-pkg/src/manifest.rs @@ -9,7 +9,7 @@ use std::{ sync::Arc, }; -use sway_core::{language::parsed::TreeType, parse}; +use sway_core::{language::parsed::TreeType, parse_tree_type}; pub use sway_types::ConfigTimeConstant; use sway_utils::constants; @@ -277,14 +277,14 @@ impl PackageManifestFile { /// Parse and return the associated project's program type. pub fn program_type(&self) -> Result { let entry_string = self.entry_string()?; - let parse_res = parse(entry_string, None); - match parse_res.value { - Some(parse_program) => Ok(parse_program.kind), - None => bail!(parsing_failed(&self.project.name, parse_res.errors)), - } + let parse_res = parse_tree_type(entry_string); + parse_res + .value + .ok_or_else(|| parsing_failed(&self.project.name, parse_res.errors)) } - /// Given the current directory and expected program type, determines whether the correct program type is present. + /// Given the current directory and expected program type, + /// determines whether the correct program type is present. pub fn check_program_type(&self, expected_types: Vec) -> Result<()> { let parsed_type = self.program_type()?; if !expected_types.contains(&parsed_type) { diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 068b50f6eb6..71fed3fdd01 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -25,9 +25,12 @@ use std::{ path::{Path, PathBuf}, str::FromStr, }; -use sway_core::fuel_prelude::{ - fuel_crypto, - fuel_tx::{self, Contract, ContractId, StorageSlot}, +use sway_core::{ + fuel_prelude::{ + fuel_crypto, + fuel_tx::{self, Contract, ContractId, StorageSlot}, + }, + TypeEngine, }; use sway_core::{ language::{ @@ -2094,8 +2097,9 @@ pub fn dependency_namespace( graph: &Graph, node: NodeIx, constants: BTreeMap, + type_engine: &TypeEngine, ) -> Result> { - let mut namespace = namespace::Module::default_with_constants(constants)?; + let mut namespace = namespace::Module::default_with_constants(type_engine, constants)?; // Add direct dependencies. let mut core_added = false; @@ -2126,7 +2130,7 @@ pub fn dependency_namespace( public: true, }; constants.insert(contract_dep_constant_name.to_string(), contract_id_constant); - namespace::Module::default_with_constants(constants)? + namespace::Module::default_with_constants(type_engine, constants)? } }; namespace.insert_submodule(dep_name, dep_namespace); @@ -2144,10 +2148,18 @@ pub fn dependency_namespace( } } - namespace.star_import_with_reexports(&[CORE, PRELUDE].map(Ident::new_no_span), &[]); + namespace.star_import_with_reexports( + &[CORE, PRELUDE].map(Ident::new_no_span), + &[], + type_engine, + ); if has_std_dep(graph, node) { - namespace.star_import_with_reexports(&[STD, PRELUDE].map(Ident::new_no_span), &[]); + namespace.star_import_with_reexports( + &[STD, PRELUDE].map(Ident::new_no_span), + &[], + type_engine, + ); } Ok(namespace) @@ -2207,6 +2219,7 @@ fn find_core_dep(graph: &Graph, node: NodeIx) -> Option { /// Compiles the package to an AST. pub fn compile_ast( + type_engine: &TypeEngine, manifest: &PackageManifestFile, build_profile: &BuildProfile, namespace: namespace::Module, @@ -2214,7 +2227,8 @@ pub fn compile_ast( let source = manifest.entry_string()?; let sway_build_config = sway_build_config(manifest.dir(), &manifest.entry_path(), build_profile)?; - let ast_res = sway_core::compile_to_ast(source, namespace, Some(&sway_build_config)); + let ast_res = + sway_core::compile_to_ast(type_engine, source, namespace, Some(&sway_build_config)); Ok(ast_res) } @@ -2241,6 +2255,7 @@ pub fn compile( manifest: &PackageManifestFile, build_profile: &BuildProfile, namespace: namespace::Module, + type_engine: &TypeEngine, source_map: &mut SourceMap, ) -> Result<(BuiltPackage, namespace::Root)> { // Time the given expression and print the result if `build_config.time_phases` is true. @@ -2275,7 +2290,7 @@ pub fn compile( // First, compile to an AST. We'll update the namespace and check for JSON ABI output. let ast_res = time_expr!( "compile to ast", - compile_ast(manifest, build_profile, namespace,)? + compile_ast(type_engine, manifest, build_profile, namespace)? ); let typed_program = match ast_res.value.as_ref() { None => return fail(&ast_res.warnings, &ast_res.errors), @@ -2289,7 +2304,7 @@ pub fn compile( let mut types = vec![]; let json_abi_program = time_expr!( "generate JSON ABI program", - typed_program.generate_json_abi_program(&mut types) + typed_program.generate_json_abi_program(type_engine, &mut types) ); let storage_slots = typed_program.storage_slots.clone(); @@ -2303,7 +2318,7 @@ pub fn compile( let asm_res = time_expr!( "compile ast to asm", - sway_core::ast_to_asm(ast_res, &sway_build_config) + sway_core::ast_to_asm(type_engine, ast_res, &sway_build_config) ); let entries = asm_res .value @@ -2507,6 +2522,7 @@ pub fn build( .flat_map(|output_node| plan.node_deps(*output_node)) .collect(); + let type_engine = TypeEngine::default(); let mut lib_namespace_map = Default::default(); let mut compiled_contract_deps = HashMap::new(); for &node in plan @@ -2524,6 +2540,7 @@ pub fn build( &plan.graph, node, constants, + &type_engine, ) { Ok(o) => o, Err(errs) => { @@ -2531,7 +2548,14 @@ pub fn build( bail!("Failed to compile {}", pkg.name); } }; - let res = compile(pkg, manifest, profile, dep_namespace, &mut source_map)?; + let res = compile( + pkg, + manifest, + profile, + dep_namespace, + &type_engine, + &mut source_map, + )?; let (mut built_package, namespace) = res; // If the current node is a contract dependency, collect the contract_id if plan @@ -2681,7 +2705,11 @@ type ParseAndTypedPrograms = CompileResult<(ParseProgram, Option) /// Compile the entire forc package and return the parse and typed programs /// of the dependancies and project. /// The final item in the returned vector is the project. -pub fn check(plan: &BuildPlan, terse_mode: bool) -> anyhow::Result> { +pub fn check( + plan: &BuildPlan, + terse_mode: bool, + type_engine: &TypeEngine, +) -> anyhow::Result> { //TODO remove once type engine isn't global anymore. sway_core::clear_lazy_statics(); let mut lib_namespace_map = Default::default(); @@ -2700,13 +2728,14 @@ pub fn check(plan: &BuildPlan, terse_mode: bool) -> anyhow::Result { @@ -2716,7 +2745,7 @@ pub fn check(plan: &BuildPlan, terse_mode: bool) -> anyhow::Result program, }; - let ast_result = sway_core::parsed_to_ast(&parse_program, dep_namespace); + let ast_result = sway_core::parsed_to_ast(type_engine, &parse_program, dep_namespace); warnings.extend(ast_result.warnings); errors.extend(ast_result.errors); @@ -2750,6 +2779,7 @@ pub fn check(plan: &BuildPlan, terse_mode: bool) -> anyhow::Result anyhow::Result> { let profile = BuildProfile { terse: terse_mode, @@ -2757,7 +2787,11 @@ pub fn parse( }; let source = manifest.entry_string()?; let sway_build_config = sway_build_config(manifest.dir(), &manifest.entry_path(), &profile)?; - Ok(sway_core::parse(source, Some(&sway_build_config))) + Ok(sway_core::parse( + source, + type_engine, + Some(&sway_build_config), + )) } /// Attempt to find a `Forc.toml` with the given project name within the given directory. diff --git a/forc-plugins/forc-doc/src/descriptor.rs b/forc-plugins/forc-doc/src/descriptor.rs index da50ff26c9c..1a9377e529a 100644 --- a/forc-plugins/forc-doc/src/descriptor.rs +++ b/forc-plugins/forc-doc/src/descriptor.rs @@ -10,10 +10,10 @@ use sway_core::{ }; use sway_types::Spanned; -#[derive(Eq, PartialEq, Debug)] // TODO: See if there's a way we can use the TyDeclarations directly // /// The type of [TyDeclaration] documented by the [Descriptor]. +#[derive(Debug)] pub(crate) enum DescriptorType { Struct(TyStructDeclaration), Enum(TyEnumDeclaration), @@ -24,6 +24,7 @@ pub(crate) enum DescriptorType { Function(TyFunctionDeclaration), Const(Box), } + impl DescriptorType { /// Converts the [DescriptorType] to a `&str` name for HTML file name creation. pub fn as_str(&self) -> &'static str { @@ -41,7 +42,6 @@ impl DescriptorType { } } -#[derive(Eq, PartialEq)] /// Used in deciding whether or not a [Declaration] is documentable. pub(crate) enum Descriptor { Documentable { @@ -52,6 +52,7 @@ pub(crate) enum Descriptor { }, NonDocumentable, } + impl Descriptor { pub(crate) fn from_typed_decl(d: &TyDeclaration, module_prefix: Vec) -> Result { use TyDeclaration::*; diff --git a/forc-plugins/forc-doc/src/main.rs b/forc-plugins/forc-doc/src/main.rs index d434dd6ba71..9d0d5d73177 100644 --- a/forc-plugins/forc-doc/src/main.rs +++ b/forc-plugins/forc-doc/src/main.rs @@ -11,6 +11,7 @@ use std::{ process::Command as Process, {fs, path::PathBuf}, }; +use sway_core::TypeEngine; use crate::{ doc::{Document, Documentation}, @@ -54,7 +55,8 @@ pub fn main() -> Result<()> { let lock_path = manifest.lock_path()?; let plan = pkg::BuildPlan::from_lock_and_manifests(&lock_path, &member_manifests, locked, offline)?; - let compilation = pkg::check(&plan, silent)? + let type_engine = TypeEngine::default(); + let compilation = pkg::check(&plan, silent, &type_engine)? .pop() .expect("there is guaranteed to be at least one elem in the vector"); let raw_docs: Documentation = Document::from_ty_program(&compilation, no_deps)?; diff --git a/forc/src/cli/commands/check.rs b/forc/src/cli/commands/check.rs index fe7a795940b..7c81cd3dc98 100644 --- a/forc/src/cli/commands/check.rs +++ b/forc/src/cli/commands/check.rs @@ -1,6 +1,7 @@ use crate::ops::forc_check; use anyhow::Result; use clap::Parser; +use sway_core::TypeEngine; /// Check the current or target project and all of its dependencies for errors. /// @@ -25,7 +26,8 @@ pub struct Command { } pub(crate) fn exec(command: Command) -> Result<()> { - let res = forc_check::check(command)?; + let type_engine = TypeEngine::default(); + let res = forc_check::check(command, &type_engine)?; if !res.is_ok() { anyhow::bail!("unable to type check"); } diff --git a/forc/src/ops/forc_check.rs b/forc/src/ops/forc_check.rs index 2fbf1b3f404..115df958bef 100644 --- a/forc/src/ops/forc_check.rs +++ b/forc/src/ops/forc_check.rs @@ -3,9 +3,12 @@ use anyhow::Result; use forc_pkg::{self as pkg}; use pkg::manifest::ManifestFile; use std::path::PathBuf; -use sway_core::{language::ty, CompileResult}; +use sway_core::{language::ty, CompileResult, TypeEngine}; -pub fn check(command: CheckCommand) -> Result> { +pub fn check( + command: CheckCommand, + type_engine: &TypeEngine, +) -> Result> { let CheckCommand { path, offline_mode: offline, @@ -24,7 +27,7 @@ pub fn check(command: CheckCommand) -> Result> { let plan = pkg::BuildPlan::from_lock_and_manifests(&lock_path, &member_manifests, locked, offline)?; - let mut v = pkg::check(&plan, terse_mode)?; + let mut v = pkg::check(&plan, terse_mode, type_engine)?; let res = v .pop() .expect("there is guaranteed to be at least one elem in the vector") diff --git a/sway-core/Cargo.toml b/sway-core/Cargo.toml index 7e23ba03f65..4ae646936a3 100644 --- a/sway-core/Cargo.toml +++ b/sway-core/Cargo.toml @@ -14,6 +14,7 @@ derivative = "2.2.0" dirs = "3.0" either = "1.6" fuel-vm = { version = "0.22", features = ["serde"] } +hashbrown = "0.13.1" hex = { version = "0.4", optional = true } im = "15.0" itertools = "0.10" diff --git a/sway-core/src/concurrent_slab.rs b/sway-core/src/concurrent_slab.rs index ec9cd664128..da0b29f5df9 100644 --- a/sway-core/src/concurrent_slab.rs +++ b/sway-core/src/concurrent_slab.rs @@ -3,7 +3,7 @@ use std::{fmt, sync::RwLock}; use crate::{ declaration_engine::{declaration_id::DeclarationId, declaration_wrapper::DeclarationWrapper}, type_system::TypeId, - TypeInfo, + PartialEqWithTypeEngine, TypeEngine, TypeInfo, }; #[derive(Debug)] @@ -22,22 +22,29 @@ where } } -impl fmt::Display for ConcurrentSlab +impl ConcurrentSlab { + pub fn with_slice(&self, run: impl FnOnce(&[T]) -> R) -> R { + run(&self.inner.read().unwrap()) + } +} + +pub struct ListDisplay { + pub list: I, +} + +impl fmt::Display for ListDisplay where - T: fmt::Display, + I::Item: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let inner = self.inner.read().unwrap(); - write!( - f, - "{}", - inner - .iter() - .enumerate() - .map(|(i, value)| { format!("{:<10}\t->\t{}", i, value) }) - .collect::>() - .join("\n"), - ) + let fmt_elems = self + .list + .clone() + .into_iter() + .enumerate() + .map(|(i, value)| format!("{:<10}\t->\t{}", i, value)) + .collect::>(); + write!(f, "{}", fmt_elems.join("\n")) } } @@ -66,11 +73,6 @@ where let inner = self.inner.read().unwrap(); inner.iter().any(f) } - - pub fn size(&self) -> usize { - let inner = self.inner.read().unwrap(); - inner.len() - } } impl ConcurrentSlab { @@ -79,7 +81,9 @@ impl ConcurrentSlab { index: TypeId, prev_value: &TypeInfo, new_value: TypeInfo, + type_engine: &TypeEngine, ) -> Option { + let index = index.index(); // The comparison below ends up calling functions in the slab, which // can lead to deadlocks if we used a single read/write lock. // So we split the operation: we do the read only operations with @@ -87,14 +91,14 @@ impl ConcurrentSlab { // we get a write lock for writing into the slab. { let inner = self.inner.read().unwrap(); - let actual_prev_value = &inner[*index]; - if actual_prev_value != prev_value { + let actual_prev_value = &inner[index]; + if !actual_prev_value.eq(prev_value, type_engine) { return Some(actual_prev_value.clone()); } } let mut inner = self.inner.write().unwrap(); - inner[*index] = new_value; + inner[index] = new_value; None } } diff --git a/sway-core/src/control_flow_analysis/analyze_return_paths.rs b/sway-core/src/control_flow_analysis/analyze_return_paths.rs index 0688c8b5adb..c665049618e 100644 --- a/sway-core/src/control_flow_analysis/analyze_return_paths.rs +++ b/sway-core/src/control_flow_analysis/analyze_return_paths.rs @@ -13,13 +13,14 @@ use sway_types::{ident::Ident, span::Span, Spanned}; impl ControlFlowGraph { pub(crate) fn construct_return_path_graph( + type_engine: &TypeEngine, module_nodes: &[ty::TyAstNode], ) -> Result { let mut graph = ControlFlowGraph::default(); // do a depth first traversal and cover individual inner ast nodes let mut leaves = vec![]; for ast_entrypoint in module_nodes { - let l_leaves = connect_node(ast_entrypoint, &mut graph, &leaves)?.0; + let l_leaves = connect_node(type_engine, ast_entrypoint, &mut graph, &leaves)?.0; if let NodeConnection::NextStep(nodes) = l_leaves { leaves = nodes; } @@ -33,7 +34,7 @@ impl ControlFlowGraph { /// and the functions namespace and validating that all paths leading to the function exit node /// return the same type. Additionally, if a function has a return type, all paths must indeed /// lead to the function exit node. - pub(crate) fn analyze_return_paths(&self) -> Vec { + pub(crate) fn analyze_return_paths(&self, type_engine: &TypeEngine) -> Vec { let mut errors = vec![]; for ( name, @@ -46,6 +47,7 @@ impl ControlFlowGraph { { // For every node connected to the entry point errors.append(&mut self.ensure_all_paths_reach_exit( + type_engine, *entry_point, *exit_point, name, @@ -57,6 +59,7 @@ impl ControlFlowGraph { fn ensure_all_paths_reach_exit( &self, + type_engine: &TypeEngine, entry_point: EntryPoint, exit_point: ExitPoint, function_name: &Ident, @@ -98,7 +101,7 @@ impl ControlFlowGraph { // different. To save some code duplication, span, function_name: function_name.clone(), - ty: return_ty.to_string(), + ty: type_engine.help_out(return_ty).to_string(), }); } next_rovers.append(&mut neighbors); @@ -119,6 +122,7 @@ enum NodeConnection { } fn connect_node( + type_engine: &TypeEngine, node: &ty::TyAstNode, graph: &mut ControlFlowGraph, leaves: &[NodeIndex], @@ -157,7 +161,8 @@ fn connect_node( // We need to dig into the body of the while loop in case there is a break or a // continue at some level. - let (l_leaves, inner_returns) = depth_first_insertion_code_block(body, graph, &leaves)?; + let (l_leaves, inner_returns) = + depth_first_insertion_code_block(type_engine, body, graph, &leaves)?; // insert edges from end of block back to beginning of it for leaf in &l_leaves { @@ -185,13 +190,21 @@ fn connect_node( } ty::TyAstNodeContent::SideEffect => Ok((NodeConnection::NextStep(leaves.to_vec()), vec![])), ty::TyAstNodeContent::Declaration(decl) => Ok(( - NodeConnection::NextStep(connect_declaration(node, decl, graph, span, leaves)?), + NodeConnection::NextStep(connect_declaration( + type_engine, + node, + decl, + graph, + span, + leaves, + )?), vec![], )), } } fn connect_declaration( + type_engine: &TypeEngine, node: &ty::TyAstNode, decl: &ty::TyDeclaration, graph: &mut ControlFlowGraph, @@ -219,7 +232,7 @@ fn connect_declaration( for leaf in leaves { graph.add_edge(*leaf, entry_node, "".into()); } - connect_typed_fn_decl(&fn_decl, graph, entry_node, span)?; + connect_typed_fn_decl(type_engine, &fn_decl, graph, entry_node, span)?; Ok(leaves.to_vec()) } ImplTrait(decl_id) => { @@ -238,7 +251,7 @@ fn connect_declaration( .map(|decl_id| de_get_function(decl_id, &trait_name.span())) .collect::, CompileError>>()?; - connect_impl_trait(&trait_name, graph, &methods, entry_node)?; + connect_impl_trait(type_engine, &trait_name, graph, &methods, entry_node)?; Ok(leaves.to_vec()) } ErrorRecovery(_) => Ok(leaves.to_vec()), @@ -251,6 +264,7 @@ fn connect_declaration( /// Additionally, we insert the trait's methods into the method namespace in order to /// track which exact methods are dead code. fn connect_impl_trait( + type_engine: &TypeEngine, trait_name: &CallPath, graph: &mut ControlFlowGraph, methods: &[ty::TyFunctionDeclaration], @@ -266,7 +280,13 @@ fn connect_impl_trait( graph.add_edge(entry_node, fn_decl_entry_node, "".into()); // connect the impl declaration node to the functions themselves, as all trait functions are // public if the trait is in scope - connect_typed_fn_decl(fn_decl, graph, fn_decl_entry_node, fn_decl.span.clone())?; + connect_typed_fn_decl( + type_engine, + fn_decl, + graph, + fn_decl_entry_node, + fn_decl.span.clone(), + )?; methods_and_indexes.push((fn_decl.name.clone(), fn_decl_entry_node)); } // Now, insert the methods into the trait method namespace. @@ -290,13 +310,15 @@ fn connect_impl_trait( /// has no entry points, since it is just a declaration. /// When something eventually calls it, it gets connected to the declaration. fn connect_typed_fn_decl( + type_engine: &TypeEngine, fn_decl: &ty::TyFunctionDeclaration, graph: &mut ControlFlowGraph, entry_node: NodeIndex, _span: Span, ) -> Result<(), CompileError> { let fn_exit_node = graph.add_node(format!("\"{}\" fn exit", fn_decl.name.as_str()).into()); - let return_nodes = depth_first_insertion_code_block(&fn_decl.body, graph, &[entry_node])?.0; + let return_nodes = + depth_first_insertion_code_block(type_engine, &fn_decl.body, graph, &[entry_node])?.0; for node in return_nodes { graph.add_edge(node, fn_exit_node, "return".into()); } @@ -304,7 +326,8 @@ fn connect_typed_fn_decl( let namespace_entry = FunctionNamespaceEntry { entry_point: entry_node, exit_point: fn_exit_node, - return_type: to_typeinfo(fn_decl.return_type, &fn_decl.return_type_span) + return_type: type_engine + .to_typeinfo(fn_decl.return_type, &fn_decl.return_type_span) .unwrap_or_else(|_| TypeInfo::Tuple(Vec::new())), }; graph @@ -316,6 +339,7 @@ fn connect_typed_fn_decl( type ReturnStatementNodes = Vec; fn depth_first_insertion_code_block( + type_engine: &TypeEngine, node_content: &ty::TyCodeBlock, graph: &mut ControlFlowGraph, leaves: &[NodeIndex], @@ -323,7 +347,7 @@ fn depth_first_insertion_code_block( let mut leaves = leaves.to_vec(); let mut return_nodes = vec![]; for node in node_content.contents.iter() { - let (this_node, inner_returns) = connect_node(node, graph, &leaves)?; + let (this_node, inner_returns) = connect_node(type_engine, node, graph, &leaves)?; match this_node { NodeConnection::NextStep(nodes) => leaves = nodes, NodeConnection::Return(node) => { diff --git a/sway-core/src/control_flow_analysis/dead_code_analysis.rs b/sway-core/src/control_flow_analysis/dead_code_analysis.rs index 005603a1810..fcab989e01a 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -2,7 +2,8 @@ use super::*; use crate::{ declaration_engine::declaration_engine::*, language::{parsed::TreeType, ty, CallPath, Visibility}, - type_system::{to_typeinfo, TypeInfo}, + type_system::TypeInfo, + TypeEngine, }; use petgraph::{prelude::NodeIndex, visit::Dfs}; use std::collections::BTreeSet; @@ -94,6 +95,7 @@ impl ControlFlowGraph { } pub(crate) fn append_module_to_dead_code_graph( + type_engine: &TypeEngine, module_nodes: &[ty::TyAstNode], tree_type: &TreeType, graph: &mut ControlFlowGraph, @@ -103,8 +105,14 @@ impl ControlFlowGraph { let mut leaves = vec![]; let exit_node = Some(graph.add_node(("Program exit".to_string()).into())); for ast_entrypoint in module_nodes { - let (l_leaves, _new_exit_node) = - connect_node(ast_entrypoint, graph, &leaves, exit_node, tree_type)?; + let (l_leaves, _new_exit_node) = connect_node( + type_engine, + ast_entrypoint, + graph, + &leaves, + exit_node, + tree_type, + )?; leaves = l_leaves; } @@ -203,6 +211,7 @@ fn entry_points( } fn connect_node( + type_engine: &TypeEngine, node: &ty::TyAstNode, graph: &mut ControlFlowGraph, leaves: &[NodeIndex], @@ -220,6 +229,7 @@ fn connect_node( // evaluate the expression let return_contents = connect_expression( + type_engine, &expr.expression, graph, &[this_index], @@ -251,6 +261,7 @@ fn connect_node( ( connect_expression( + type_engine, expr_variant, graph, &[entry], @@ -275,14 +286,25 @@ fn connect_node( graph.add_edge(*leaf, decl_node, "".into()); } ( - connect_declaration(decl, graph, decl_node, span, exit_node, tree_type, leaves)?, + connect_declaration( + type_engine, + decl, + graph, + decl_node, + span, + exit_node, + tree_type, + leaves, + )?, exit_node, ) } }) } +#[allow(clippy::too_many_arguments)] fn connect_declaration( + type_engine: &TypeEngine, decl: &ty::TyDeclaration, graph: &mut ControlFlowGraph, entry_node: NodeIndex, @@ -305,6 +327,7 @@ fn connect_declaration( Ok(leaves.to_vec()) } else { connect_expression( + type_engine, &body.expression, graph, &[entry_node], @@ -320,6 +343,7 @@ fn connect_declaration( de_get_constant(decl_id.clone(), &span)?; graph.namespace.insert_constant(name, entry_node); connect_expression( + type_engine, &value.expression, graph, &[entry_node], @@ -331,7 +355,15 @@ fn connect_declaration( } FunctionDeclaration(decl_id) => { let fn_decl = de_get_function(decl_id.clone(), &decl.span())?; - connect_typed_fn_decl(&fn_decl, graph, entry_node, span, exit_node, tree_type)?; + connect_typed_fn_decl( + type_engine, + &fn_decl, + graph, + entry_node, + span, + exit_node, + tree_type, + )?; Ok(leaves.to_vec()) } TraitDeclaration(decl_id) => { @@ -366,7 +398,14 @@ fn connect_declaration( .map(|decl_id| de_get_function(decl_id, &trait_name.span())) .collect::, CompileError>>()?; - connect_impl_trait(&trait_name, graph, &methods, entry_node, tree_type)?; + connect_impl_trait( + type_engine, + &trait_name, + graph, + &methods, + entry_node, + tree_type, + )?; Ok(leaves.to_vec()) } StorageDeclaration(decl_id) => { @@ -422,6 +461,7 @@ fn connect_struct_declaration( /// Additionally, we insert the trait's methods into the method namespace in order to /// track which exact methods are dead code. fn connect_impl_trait( + type_engine: &TypeEngine, trait_name: &CallPath, graph: &mut ControlFlowGraph, methods: &[ty::TyFunctionDeclaration], @@ -450,6 +490,7 @@ fn connect_impl_trait( // connect the impl declaration node to the functions themselves, as all trait functions are // public if the trait is in scope connect_typed_fn_decl( + type_engine, fn_decl, graph, fn_decl_entry_node, @@ -545,6 +586,7 @@ fn connect_enum_declaration( /// has no entry points, since it is just a declaration. /// When something eventually calls it, it gets connected to the declaration. fn connect_typed_fn_decl( + type_engine: &TypeEngine, fn_decl: &ty::TyFunctionDeclaration, graph: &mut ControlFlowGraph, entry_node: NodeIndex, @@ -554,6 +596,7 @@ fn connect_typed_fn_decl( ) -> Result<(), CompileError> { let fn_exit_node = graph.add_node(format!("\"{}\" fn exit", fn_decl.name.as_str()).into()); let (_exit_nodes, _exit_node) = depth_first_insertion_code_block( + type_engine, &fn_decl.body, graph, &[entry_node], @@ -566,8 +609,9 @@ fn connect_typed_fn_decl( // not sure how correct it is to default to Unit here... // I think types should all be resolved by now. - let ty = - to_typeinfo(fn_decl.return_type, &span).unwrap_or_else(|_| TypeInfo::Tuple(Vec::new())); + let ty = type_engine + .to_typeinfo(fn_decl.return_type, &span) + .unwrap_or_else(|_| TypeInfo::Tuple(Vec::new())); let namespace_entry = FunctionNamespaceEntry { entry_point: entry_node, @@ -579,7 +623,7 @@ fn connect_typed_fn_decl( .namespace .insert_function(fn_decl.name.clone(), namespace_entry); - connect_fn_params_struct_enums(fn_decl, graph, entry_node)?; + connect_fn_params_struct_enums(type_engine, fn_decl, graph, entry_node)?; Ok(()) } @@ -588,12 +632,13 @@ fn connect_typed_fn_decl( // corresponding struct/enum declaration to the function entry node, thus // making sure they are considered used by the DCA pass. fn connect_fn_params_struct_enums( + type_engine: &TypeEngine, fn_decl: &ty::TyFunctionDeclaration, graph: &mut ControlFlowGraph, fn_decl_entry_node: NodeIndex, ) -> Result<(), CompileError> { for fn_param in &fn_decl.parameters { - let ty = to_typeinfo(fn_param.type_id, &fn_param.type_span)?; + let ty = type_engine.to_typeinfo(fn_param.type_id, &fn_param.type_span)?; match ty { TypeInfo::Enum { name, .. } => { let ty_index = match graph.namespace.find_enum(&name) { @@ -616,6 +661,7 @@ fn connect_fn_params_struct_enums( } fn depth_first_insertion_code_block( + type_engine: &TypeEngine, node_content: &ty::TyCodeBlock, graph: &mut ControlFlowGraph, leaves: &[NodeIndex], @@ -625,7 +671,8 @@ fn depth_first_insertion_code_block( let mut leaves = leaves.to_vec(); let mut exit_node = exit_node; for node in node_content.contents.iter() { - let (this_node, l_exit_node) = connect_node(node, graph, &leaves, exit_node, tree_type)?; + let (this_node, l_exit_node) = + connect_node(type_engine, node, graph, &leaves, exit_node, tree_type)?; leaves = this_node; exit_node = l_exit_node; } @@ -634,7 +681,9 @@ fn depth_first_insertion_code_block( /// connects any inner parts of an expression to the graph /// note the main expression node has already been inserted +#[allow(clippy::too_many_arguments)] fn connect_expression( + type_engine: &TypeEngine, expr_variant: &ty::TyExpressionVariant, graph: &mut ControlFlowGraph, leaves: &[NodeIndex], @@ -679,6 +728,7 @@ fn connect_expression( let mut current_leaf = vec![fn_entrypoint]; for (_name, arg) in arguments { current_leaf = connect_expression( + type_engine, &arg.expression, graph, ¤t_leaf, @@ -706,6 +756,7 @@ fn connect_expression( } LazyOperator { lhs, rhs, .. } => { let lhs_expr = connect_expression( + type_engine, &lhs.expression, graph, leaves, @@ -715,6 +766,7 @@ fn connect_expression( lhs.span.clone(), )?; let rhs_expr = connect_expression( + type_engine, &rhs.expression, graph, leaves, @@ -754,6 +806,7 @@ fn connect_expression( } => { // connect this particular instantiation to its variants declaration connect_enum_instantiation( + type_engine, enum_decl, contents, variant_name, @@ -769,6 +822,7 @@ fn connect_expression( r#else, } => { let condition_expr = connect_expression( + type_engine, &condition.expression, graph, leaves, @@ -778,6 +832,7 @@ fn connect_expression( condition.span.clone(), )?; let then_expr = connect_expression( + type_engine, &then.expression, graph, leaves, @@ -789,6 +844,7 @@ fn connect_expression( let else_expr = if let Some(else_expr) = r#else { connect_expression( + type_engine, &else_expr.expression, graph, leaves, @@ -804,7 +860,7 @@ fn connect_expression( Ok([condition_expr, then_expr, else_expr].concat()) } CodeBlock(a @ ty::TyCodeBlock { .. }) => { - connect_code_block(a, graph, leaves, exit_node, tree_type) + connect_code_block(type_engine, a, graph, leaves, exit_node, tree_type) } StructExpression { struct_name, @@ -828,6 +884,7 @@ fn connect_expression( // for every field, connect its expression for ty::TyStructExpressionField { value, .. } in fields { current_leaf = connect_expression( + type_engine, &value.expression, graph, ¤t_leaf, @@ -849,9 +906,9 @@ fn connect_expression( resolved_type_of_parent, .. } => { - let resolved_type_of_parent = - to_typeinfo(*resolved_type_of_parent, &field_to_access.span) - .unwrap_or_else(|_| TypeInfo::Tuple(Vec::new())); + let resolved_type_of_parent = type_engine + .to_typeinfo(*resolved_type_of_parent, &field_to_access.span) + .unwrap_or_else(|_| TypeInfo::Tuple(Vec::new())); assert!(matches!(resolved_type_of_parent, TypeInfo::Struct { .. })); let resolved_type_of_parent = match resolved_type_of_parent { @@ -892,6 +949,7 @@ fn connect_expression( for ty::TyAsmRegisterDeclaration { initializer, .. } in registers { current_leaf = match initializer { Some(initializer) => connect_expression( + type_engine, &initializer.expression, graph, ¤t_leaf, @@ -923,6 +981,7 @@ fn connect_expression( // for every field, connect its expression for value in fields { current_leaf = connect_expression( + type_engine, &value.expression, graph, ¤t_leaf, @@ -940,6 +999,7 @@ fn connect_expression( Ok(vec![exit]) } AbiCast { address, .. } => connect_expression( + type_engine, &address.expression, graph, leaves, @@ -953,6 +1013,7 @@ fn connect_expression( .iter() .map(|elem| { connect_expression( + type_engine, &elem.expression, graph, leaves, @@ -967,6 +1028,7 @@ fn connect_expression( } ArrayIndex { prefix, index } => { let prefix_idx = connect_expression( + type_engine, &prefix.expression, graph, leaves, @@ -976,6 +1038,7 @@ fn connect_expression( prefix.span.clone(), )?; let index_idx = connect_expression( + type_engine, &index.expression, graph, leaves, @@ -988,6 +1051,7 @@ fn connect_expression( } TupleElemAccess { prefix, .. } => { let prefix_idx = connect_expression( + type_engine, &prefix.expression, graph, leaves, @@ -1013,7 +1077,8 @@ fn connect_expression( Ok(vec![this_ix]) } IntrinsicFunction(kind) => { - let prefix_idx = connect_intrinsic_function(kind, graph, leaves, exit_node, tree_type)?; + let prefix_idx = + connect_intrinsic_function(type_engine, kind, graph, leaves, exit_node, tree_type)?; Ok(prefix_idx) } AbiName(abi_name) => { @@ -1030,6 +1095,7 @@ fn connect_expression( } FunctionParameter => Ok(leaves.to_vec()), EnumTag { exp } => connect_expression( + type_engine, &exp.expression, graph, leaves, @@ -1039,6 +1105,7 @@ fn connect_expression( exp.span.clone(), ), UnsafeDowncast { exp, .. } => connect_expression( + type_engine, &exp.expression, graph, leaves, @@ -1064,8 +1131,14 @@ fn connect_expression( "condition is initially false".into(), ); let mut leaves = vec![entry]; - let (l_leaves, _l_exit_node) = - depth_first_insertion_code_block(body, graph, &leaves, exit_node, tree_type)?; + let (l_leaves, _l_exit_node) = depth_first_insertion_code_block( + type_engine, + body, + graph, + &leaves, + exit_node, + tree_type, + )?; // insert edges from end of block back to beginning of it for leaf in &l_leaves { graph.add_edge(*leaf, entry, "loop repeats".into()); @@ -1092,6 +1165,7 @@ fn connect_expression( Ok(vec![]) } Reassignment(typed_reassignment) => connect_expression( + type_engine, &typed_reassignment.rhs.expression, graph, leaves, @@ -1101,6 +1175,7 @@ fn connect_expression( typed_reassignment.rhs.clone().span, ), StorageReassignment(typed_storage_reassignment) => connect_expression( + type_engine, &typed_storage_reassignment.rhs.expression, graph, leaves, @@ -1115,6 +1190,7 @@ fn connect_expression( graph.add_edge(*leaf, this_index, "".into()); } let return_contents = connect_expression( + type_engine, &exp.expression, graph, &[this_index], @@ -1137,6 +1213,7 @@ fn connect_expression( } fn connect_intrinsic_function( + type_engine: &TypeEngine, ty::TyIntrinsicFunctionKind { kind, arguments, .. }: &ty::TyIntrinsicFunctionKind, @@ -1152,6 +1229,7 @@ fn connect_intrinsic_function( let mut result = vec![node]; let _ = arguments.iter().try_fold(&mut result, |accum, exp| { let mut res = connect_expression( + type_engine, &exp.expression, graph, leaves, @@ -1167,6 +1245,7 @@ fn connect_intrinsic_function( } fn connect_code_block( + type_engine: &TypeEngine, block: &ty::TyCodeBlock, graph: &mut ControlFlowGraph, leaves: &[NodeIndex], @@ -1180,7 +1259,15 @@ fn connect_code_block( } let mut current_leaf = vec![block_entry]; for node in contents { - current_leaf = connect_node(node, graph, ¤t_leaf, exit_node, tree_type)?.0; + current_leaf = connect_node( + type_engine, + node, + graph, + ¤t_leaf, + exit_node, + tree_type, + )? + .0; } let block_exit = graph.add_node("Code block exit".into()); @@ -1190,7 +1277,9 @@ fn connect_code_block( Ok(vec![block_exit]) } +#[allow(clippy::too_many_arguments)] fn connect_enum_instantiation( + type_engine: &TypeEngine, enum_decl: &ty::TyEnumDeclaration, contents: &Option>, variant_name: &Ident, @@ -1228,6 +1317,7 @@ fn connect_enum_instantiation( // add edge from the entry of the enum instantiation to the body of the instantiation if let Some(instantiator) = contents { let instantiator_contents = connect_expression( + type_engine, &instantiator.expression, graph, &[enum_instantiation_entry_idx], diff --git a/sway-core/src/declaration_engine/declaration_engine.rs b/sway-core/src/declaration_engine/declaration_engine.rs index 5160870b386..abcffc51bf8 100644 --- a/sway-core/src/declaration_engine/declaration_engine.rs +++ b/sway-core/src/declaration_engine/declaration_engine.rs @@ -8,7 +8,11 @@ use lazy_static::lazy_static; use sway_error::error::CompileError; use sway_types::{Span, Spanned}; -use crate::{concurrent_slab::ConcurrentSlab, language::ty}; +use crate::{ + concurrent_slab::{ConcurrentSlab, ListDisplay}, + language::ty, + PartialEqWithTypeEngine, TypeEngine, +}; use super::{declaration_id::DeclarationId, declaration_wrapper::DeclarationWrapper}; @@ -25,7 +29,10 @@ pub struct DeclarationEngine { impl fmt::Display for DeclarationEngine { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "DeclarationEngine {{\n{}\n}}", self.slab) + self.slab.with_slice(|elems| { + let list = ListDisplay { list: elems.iter() }; + write!(f, "DeclarationEngine {{\n{}\n}}", list) + }) } } @@ -53,7 +60,11 @@ impl DeclarationEngine { /// duplicated computation---if the parents of a [DeclarationId] have /// already been found, we do not find them again. #[allow(clippy::map_entry)] - fn find_all_parents(&self, index: DeclarationId) -> Vec { + fn find_all_parents( + &self, + index: DeclarationId, + type_engine: &TypeEngine, + ) -> Vec { let parents = self.parents.read().unwrap(); let mut acc_parents: HashMap = HashMap::new(); let mut already_checked: HashSet = HashSet::new(); @@ -67,7 +78,7 @@ impl DeclarationEngine { if !acc_parents.contains_key(&**curr_parent) { acc_parents.insert(**curr_parent, curr_parent.clone()); } - if !left_to_check.contains(curr_parent) { + if !left_to_check.iter().any(|x| x.eq(curr_parent, type_engine)) { left_to_check.push_back(curr_parent.clone()); } } @@ -227,8 +238,11 @@ pub(crate) fn de_insert(declaration_wrapper: DeclarationWrapper, span: Span) -> DECLARATION_ENGINE.insert(declaration_wrapper, span) } -pub(super) fn de_find_all_parents(index: DeclarationId) -> Vec { - DECLARATION_ENGINE.find_all_parents(index) +pub(super) fn de_find_all_parents( + index: DeclarationId, + type_engine: &TypeEngine, +) -> Vec { + DECLARATION_ENGINE.find_all_parents(index, type_engine) } pub(super) fn de_register_parent(index: &DeclarationId, parent: DeclarationId) { diff --git a/sway-core/src/declaration_engine/declaration_id.rs b/sway-core/src/declaration_engine/declaration_id.rs index 412b51c1f7d..75b78416574 100644 --- a/sway-core/src/declaration_engine/declaration_id.rs +++ b/sway-core/src/declaration_engine/declaration_id.rs @@ -4,7 +4,7 @@ use sway_types::{Span, Spanned}; use crate::{ type_system::{CopyTypes, TypeMapping}, - ReplaceSelfType, TypeId, + EqWithTypeEngine, PartialEqWithTypeEngine, ReplaceSelfType, TypeEngine, TypeId, }; use super::{ @@ -14,7 +14,7 @@ use super::{ }; /// An ID used to refer to an item in the [DeclarationEngine](super::declaration_engine::DeclarationEngine) -#[derive(Debug, Eq)] +#[derive(Debug)] pub struct DeclarationId(usize, Span); impl Clone for DeclarationId { @@ -26,9 +26,10 @@ impl Clone for DeclarationId { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for DeclarationId { - fn eq(&self, other: &Self) -> bool { - de_look_up_decl_id(self.clone()) == de_look_up_decl_id(other.clone()) +impl EqWithTypeEngine for DeclarationId {} +impl PartialEqWithTypeEngine for DeclarationId { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { + de_look_up_decl_id(self.clone()).eq(&de_look_up_decl_id(other.clone()), type_engine) } } @@ -59,28 +60,28 @@ impl Spanned for DeclarationId { } impl CopyTypes for DeclarationId { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { let mut decl = de_look_up_decl_id(self.clone()); - decl.copy_types(type_mapping); + decl.copy_types(type_mapping, type_engine); de_replace_decl_id(self.clone(), decl); } } impl ReplaceSelfType for DeclarationId { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { let mut decl = de_look_up_decl_id(self.clone()); - decl.replace_self_type(self_type); + decl.replace_self_type(type_engine, self_type); de_replace_decl_id(self.clone(), decl); } } impl ReplaceDecls for DeclarationId { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping) { + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { if let Some(new_decl_id) = decl_mapping.find_match(self) { self.0 = *new_decl_id; return; } - let all_parents = de_find_all_parents(self.clone()); + let all_parents = de_find_all_parents(self.clone(), type_engine); for parent in all_parents.into_iter() { if let Some(new_decl_id) = decl_mapping.find_match(&parent) { self.0 = *new_decl_id; @@ -104,21 +105,33 @@ impl DeclarationId { self.0 = index; } - pub(crate) fn copy_types_and_insert_new(&self, type_mapping: &TypeMapping) -> DeclarationId { + pub(crate) fn copy_types_and_insert_new( + &self, + type_mapping: &TypeMapping, + type_engine: &TypeEngine, + ) -> DeclarationId { let mut decl = de_look_up_decl_id(self.clone()); - decl.copy_types(type_mapping); + decl.copy_types(type_mapping, type_engine); de_insert(decl, self.1.clone()).with_parent(self.clone()) } - pub(crate) fn replace_self_type_and_insert_new(&self, self_type: TypeId) -> DeclarationId { + pub(crate) fn replace_self_type_and_insert_new( + &self, + type_engine: &TypeEngine, + self_type: TypeId, + ) -> DeclarationId { let mut decl = de_look_up_decl_id(self.clone()); - decl.replace_self_type(self_type); + decl.replace_self_type(type_engine, self_type); de_insert(decl, self.1.clone()).with_parent(self.clone()) } - pub(crate) fn replace_decls_and_insert_new(&self, decl_mapping: &DeclMapping) -> DeclarationId { + pub(crate) fn replace_decls_and_insert_new( + &self, + decl_mapping: &DeclMapping, + type_engine: &TypeEngine, + ) -> DeclarationId { let mut decl = de_look_up_decl_id(self.clone()); - decl.replace_decls(decl_mapping); + decl.replace_decls(decl_mapping, type_engine); de_insert(decl, self.1.clone()).with_parent(self.clone()) } } diff --git a/sway-core/src/declaration_engine/declaration_wrapper.rs b/sway-core/src/declaration_engine/declaration_wrapper.rs index 02ea12752eb..997c68ab3f1 100644 --- a/sway-core/src/declaration_engine/declaration_wrapper.rs +++ b/sway-core/src/declaration_engine/declaration_wrapper.rs @@ -6,7 +6,7 @@ use sway_types::Span; use crate::{ language::ty, type_system::{CopyTypes, TypeMapping}, - ReplaceSelfType, TypeId, + PartialEqWithTypeEngine, ReplaceSelfType, TypeEngine, TypeId, }; use super::{DeclMapping, ReplaceDecls}; @@ -37,19 +37,29 @@ impl Default for DeclarationWrapper { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for DeclarationWrapper { - fn eq(&self, other: &Self) -> bool { +impl PartialEqWithTypeEngine for DeclarationWrapper { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { match (self, other) { (DeclarationWrapper::Unknown, DeclarationWrapper::Unknown) => true, - (DeclarationWrapper::Function(l), DeclarationWrapper::Function(r)) => l == r, - (DeclarationWrapper::Trait(l), DeclarationWrapper::Trait(r)) => l == r, - (DeclarationWrapper::TraitFn(l), DeclarationWrapper::TraitFn(r)) => l == r, - (DeclarationWrapper::ImplTrait(l), DeclarationWrapper::ImplTrait(r)) => l == r, - (DeclarationWrapper::Struct(l), DeclarationWrapper::Struct(r)) => l == r, - (DeclarationWrapper::Storage(l), DeclarationWrapper::Storage(r)) => l == r, - (DeclarationWrapper::Abi(l), DeclarationWrapper::Abi(r)) => l == r, - (DeclarationWrapper::Constant(l), DeclarationWrapper::Constant(r)) => l == r, - (DeclarationWrapper::Enum(l), DeclarationWrapper::Enum(r)) => l == r, + (DeclarationWrapper::Function(l), DeclarationWrapper::Function(r)) => { + l.eq(r, type_engine) + } + (DeclarationWrapper::Trait(l), DeclarationWrapper::Trait(r)) => l.eq(r, type_engine), + (DeclarationWrapper::TraitFn(l), DeclarationWrapper::TraitFn(r)) => { + l.eq(r, type_engine) + } + (DeclarationWrapper::ImplTrait(l), DeclarationWrapper::ImplTrait(r)) => { + l.eq(r, type_engine) + } + (DeclarationWrapper::Struct(l), DeclarationWrapper::Struct(r)) => l.eq(r, type_engine), + (DeclarationWrapper::Storage(l), DeclarationWrapper::Storage(r)) => { + l.eq(r, type_engine) + } + (DeclarationWrapper::Abi(l), DeclarationWrapper::Abi(r)) => l.eq(r, type_engine), + (DeclarationWrapper::Constant(l), DeclarationWrapper::Constant(r)) => { + l.eq(r, type_engine) + } + (DeclarationWrapper::Enum(l), DeclarationWrapper::Enum(r)) => l.eq(r, type_engine), _ => false, } } @@ -62,43 +72,43 @@ impl fmt::Display for DeclarationWrapper { } impl CopyTypes for DeclarationWrapper { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { match self { DeclarationWrapper::Unknown => {} - DeclarationWrapper::Function(decl) => decl.copy_types(type_mapping), - DeclarationWrapper::Trait(decl) => decl.copy_types(type_mapping), - DeclarationWrapper::TraitFn(decl) => decl.copy_types(type_mapping), - DeclarationWrapper::ImplTrait(decl) => decl.copy_types(type_mapping), - DeclarationWrapper::Struct(decl) => decl.copy_types(type_mapping), + DeclarationWrapper::Function(decl) => decl.copy_types(type_mapping, type_engine), + DeclarationWrapper::Trait(decl) => decl.copy_types(type_mapping, type_engine), + DeclarationWrapper::TraitFn(decl) => decl.copy_types(type_mapping, type_engine), + DeclarationWrapper::ImplTrait(decl) => decl.copy_types(type_mapping, type_engine), + DeclarationWrapper::Struct(decl) => decl.copy_types(type_mapping, type_engine), DeclarationWrapper::Storage(_) => {} DeclarationWrapper::Abi(_) => {} DeclarationWrapper::Constant(_) => {} - DeclarationWrapper::Enum(decl) => decl.copy_types(type_mapping), + DeclarationWrapper::Enum(decl) => decl.copy_types(type_mapping, type_engine), } } } impl ReplaceSelfType for DeclarationWrapper { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { match self { DeclarationWrapper::Unknown => {} - DeclarationWrapper::Function(decl) => decl.replace_self_type(self_type), - DeclarationWrapper::Trait(decl) => decl.replace_self_type(self_type), - DeclarationWrapper::TraitFn(decl) => decl.replace_self_type(self_type), - DeclarationWrapper::ImplTrait(decl) => decl.replace_self_type(self_type), - DeclarationWrapper::Struct(decl) => decl.replace_self_type(self_type), + DeclarationWrapper::Function(decl) => decl.replace_self_type(type_engine, self_type), + DeclarationWrapper::Trait(decl) => decl.replace_self_type(type_engine, self_type), + DeclarationWrapper::TraitFn(decl) => decl.replace_self_type(type_engine, self_type), + DeclarationWrapper::ImplTrait(decl) => decl.replace_self_type(type_engine, self_type), + DeclarationWrapper::Struct(decl) => decl.replace_self_type(type_engine, self_type), DeclarationWrapper::Storage(_) => {} DeclarationWrapper::Abi(_) => {} DeclarationWrapper::Constant(_) => {} - DeclarationWrapper::Enum(decl) => decl.replace_self_type(self_type), + DeclarationWrapper::Enum(decl) => decl.replace_self_type(type_engine, self_type), } } } impl ReplaceDecls for DeclarationWrapper { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping) { + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { if let DeclarationWrapper::Function(decl) = self { - decl.replace_decls(decl_mapping); + decl.replace_decls(decl_mapping, type_engine); } } } diff --git a/sway-core/src/declaration_engine/replace_declaration_id.rs b/sway-core/src/declaration_engine/replace_declaration_id.rs index 29ef940993b..9e6bfdfe12a 100644 --- a/sway-core/src/declaration_engine/replace_declaration_id.rs +++ b/sway-core/src/declaration_engine/replace_declaration_id.rs @@ -1,11 +1,13 @@ +use crate::TypeEngine; + use super::DeclMapping; pub(crate) trait ReplaceDecls { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping); + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine); - fn replace_decls(&mut self, decl_mapping: &DeclMapping) { + fn replace_decls(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { if !decl_mapping.is_empty() { - self.replace_decls_inner(decl_mapping); + self.replace_decls_inner(decl_mapping, type_engine); } } } diff --git a/sway-core/src/ir_generation.rs b/sway-core/src/ir_generation.rs index f76a26dddb7..08db6c5c7f7 100644 --- a/sway-core/src/ir_generation.rs +++ b/sway-core/src/ir_generation.rs @@ -13,11 +13,12 @@ use sway_types::span::Span; pub(crate) use purity::{check_function_purity, PurityEnv}; -use crate::language::ty; +use crate::{language::ty, TypeEngine}; pub fn compile_program( program: ty::TyProgram, include_tests: bool, + type_engine: &TypeEngine, ) -> Result { let test_fns = match include_tests { true => program.test_fns().collect(), @@ -42,6 +43,7 @@ pub fn compile_program( // predicates and scripts have the same codegen, their only difference is static // type-check time checks. ty::TyProgramKind::Script { main_function } => compile::compile_script( + type_engine, &mut ctx, main_function, &root.namespace, @@ -50,6 +52,7 @@ pub fn compile_program( test_fns, ), ty::TyProgramKind::Predicate { main_function } => compile::compile_predicate( + type_engine, &mut ctx, main_function, &root.namespace, @@ -64,8 +67,10 @@ pub fn compile_program( declarations, &logged_types, test_fns, + type_engine, ), ty::TyProgramKind::Library { .. } => compile::compile_library( + type_engine, &mut ctx, &root.namespace, declarations, diff --git a/sway-core/src/ir_generation/compile.rs b/sway-core/src/ir_generation/compile.rs index 91ebd123b9f..a91ee95687b 100644 --- a/sway-core/src/ir_generation/compile.rs +++ b/sway-core/src/ir_generation/compile.rs @@ -3,7 +3,8 @@ use crate::{ language::{ty, Visibility}, metadata::MetadataManager, semantic_analysis::namespace, - type_system::{look_up_type_id, LogId, TypeId}, + type_system::{LogId, TypeId}, + TypeEngine, }; use super::{ @@ -19,6 +20,7 @@ use sway_types::{span::Span, Spanned}; use std::collections::HashMap; pub(super) fn compile_script( + type_engine: &TypeEngine, context: &mut Context, main_function: ty::TyFunctionDeclaration, namespace: &namespace::Module, @@ -29,21 +31,37 @@ pub(super) fn compile_script( let module = Module::new(context, Kind::Script); let mut md_mgr = MetadataManager::default(); - compile_constants(context, &mut md_mgr, module, namespace)?; - compile_declarations(context, &mut md_mgr, module, namespace, declarations)?; + compile_constants(type_engine, context, &mut md_mgr, module, namespace)?; + compile_declarations( + type_engine, + context, + &mut md_mgr, + module, + namespace, + declarations, + )?; compile_entry_function( + type_engine, context, &mut md_mgr, module, main_function, logged_types_map, )?; - compile_tests(context, &mut md_mgr, module, logged_types_map, test_fns)?; + compile_tests( + type_engine, + context, + &mut md_mgr, + module, + logged_types_map, + test_fns, + )?; Ok(module) } pub(super) fn compile_predicate( + type_engine: &TypeEngine, context: &mut Context, main_function: ty::TyFunctionDeclaration, namespace: &namespace::Module, @@ -54,10 +72,31 @@ pub(super) fn compile_predicate( let module = Module::new(context, Kind::Predicate); let mut md_mgr = MetadataManager::default(); - compile_constants(context, &mut md_mgr, module, namespace)?; - compile_declarations(context, &mut md_mgr, module, namespace, declarations)?; - compile_entry_function(context, &mut md_mgr, module, main_function, &HashMap::new())?; - compile_tests(context, &mut md_mgr, module, logged_types, test_fns)?; + compile_constants(type_engine, context, &mut md_mgr, module, namespace)?; + compile_declarations( + type_engine, + context, + &mut md_mgr, + module, + namespace, + declarations, + )?; + compile_entry_function( + type_engine, + context, + &mut md_mgr, + module, + main_function, + &HashMap::new(), + )?; + compile_tests( + type_engine, + context, + &mut md_mgr, + module, + logged_types, + test_fns, + )?; Ok(module) } @@ -69,21 +108,44 @@ pub(super) fn compile_contract( declarations: Vec, logged_types_map: &HashMap, test_fns: Vec, + type_engine: &TypeEngine, ) -> Result { let module = Module::new(context, Kind::Contract); let mut md_mgr = MetadataManager::default(); - compile_constants(context, &mut md_mgr, module, namespace)?; - compile_declarations(context, &mut md_mgr, module, namespace, declarations)?; + compile_constants(type_engine, context, &mut md_mgr, module, namespace)?; + compile_declarations( + type_engine, + context, + &mut md_mgr, + module, + namespace, + declarations, + )?; for decl in abi_entries { - compile_abi_method(context, &mut md_mgr, module, decl, logged_types_map)?; + compile_abi_method( + context, + &mut md_mgr, + module, + decl, + logged_types_map, + type_engine, + )?; } - compile_tests(context, &mut md_mgr, module, logged_types_map, test_fns)?; + compile_tests( + type_engine, + context, + &mut md_mgr, + module, + logged_types_map, + test_fns, + )?; Ok(module) } pub(super) fn compile_library( + type_engine: &TypeEngine, context: &mut Context, namespace: &namespace::Module, declarations: Vec, @@ -93,14 +155,29 @@ pub(super) fn compile_library( let module = Module::new(context, Kind::Library); let mut md_mgr = MetadataManager::default(); - compile_constants(context, &mut md_mgr, module, namespace)?; - compile_declarations(context, &mut md_mgr, module, namespace, declarations)?; - compile_tests(context, &mut md_mgr, module, logged_types_map, test_fns)?; + compile_constants(type_engine, context, &mut md_mgr, module, namespace)?; + compile_declarations( + type_engine, + context, + &mut md_mgr, + module, + namespace, + declarations, + )?; + compile_tests( + type_engine, + context, + &mut md_mgr, + module, + logged_types_map, + test_fns, + )?; Ok(module) } pub(crate) fn compile_constants( + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -109,6 +186,7 @@ pub(crate) fn compile_constants( for decl_name in module_ns.get_all_declared_symbols() { compile_const_decl( &mut LookupEnv { + type_engine, context, md_mgr, module, @@ -121,7 +199,7 @@ pub(crate) fn compile_constants( } for submodule_ns in module_ns.submodules().values() { - compile_constants(context, md_mgr, module, submodule_ns)?; + compile_constants(type_engine, context, md_mgr, module, submodule_ns)?; } Ok(()) @@ -137,6 +215,7 @@ pub(crate) fn compile_constants( // they are monomorphised only at the instantation site. We must ignore the generic declarations // altogether anyway. fn compile_declarations( + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -149,6 +228,7 @@ fn compile_declarations( let decl = de_get_constant(decl_id.clone(), &declaration.span())?; compile_const_decl( &mut LookupEnv { + type_engine, context, md_mgr, module, @@ -192,6 +272,7 @@ fn compile_declarations( } pub(super) fn compile_function( + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -207,10 +288,11 @@ pub(super) fn compile_function( let args = ast_fn_decl .parameters .iter() - .map(|param| convert_fn_param(context, param)) + .map(|param| convert_fn_param(type_engine, context, param)) .collect::, CompileError>>()?; compile_fn_with_args( + type_engine, context, md_mgr, module, @@ -225,6 +307,7 @@ pub(super) fn compile_function( } pub(super) fn compile_entry_function( + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -233,6 +316,7 @@ pub(super) fn compile_entry_function( ) -> Result { let is_entry = true; compile_function( + type_engine, context, md_mgr, module, @@ -244,6 +328,7 @@ pub(super) fn compile_entry_function( } pub(super) fn compile_tests( + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -253,19 +338,27 @@ pub(super) fn compile_tests( test_fns .into_iter() .map(|ast_fn_decl| { - compile_entry_function(context, md_mgr, module, ast_fn_decl, logged_types_map) + compile_entry_function( + type_engine, + context, + md_mgr, + module, + ast_fn_decl, + logged_types_map, + ) }) .collect() } fn convert_fn_param( + type_engine: &TypeEngine, context: &mut Context, param: &ty::TyFunctionParameter, ) -> Result<(String, Type, Span), CompileError> { - convert_resolved_typeid(context, ¶m.type_id, ¶m.type_span).map(|ty| { + convert_resolved_typeid(type_engine, context, ¶m.type_id, ¶m.type_span).map(|ty| { ( param.name.as_str().into(), - if param.is_reference && look_up_type_id(param.type_id).is_copy_type() { + if param.is_reference && type_engine.look_up_type_id(param.type_id).is_copy_type() { Type::Pointer(Pointer::new(context, ty, param.is_mutable, None)) } else { ty @@ -277,6 +370,7 @@ fn convert_fn_param( #[allow(clippy::too_many_arguments)] fn compile_fn_with_args( + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -303,7 +397,7 @@ fn compile_fn_with_args( .map(|(name, ty, span)| (name, ty, md_mgr.span_to_md(context, &span))) .collect::>(); - let ret_type = convert_resolved_typeid(context, &return_type, &return_type_span)?; + let ret_type = convert_resolved_typeid(type_engine, context, &return_type, &return_type_span)?; let returns_by_ref = !is_entry && !ret_type.is_copy_type(); if returns_by_ref { @@ -336,7 +430,14 @@ fn compile_fn_with_args( metadata, ); - let mut compiler = FnCompiler::new(context, module, func, returns_by_ref, logged_types_map); + let mut compiler = FnCompiler::new( + type_engine, + context, + module, + func, + returns_by_ref, + logged_types_map, + ); let mut ret_val = compiler.compile_code_block(context, md_mgr, body)?; // Special case: sometimes the returned value at the end of the function block is hacked @@ -414,9 +515,10 @@ fn compile_abi_method( module: Module, ast_fn_decl: ty::TyFunctionDeclaration, logged_types_map: &HashMap, + type_engine: &TypeEngine, ) -> Result { // Use the error from .to_fn_selector_value() if possible, else make an CompileError::Internal. - let get_selector_result = ast_fn_decl.to_fn_selector_value(); + let get_selector_result = ast_fn_decl.to_fn_selector_value(type_engine); let mut warnings = Vec::new(); let mut errors = Vec::new(); let selector = match get_selector_result.ok(&mut warnings, &mut errors) { @@ -443,12 +545,13 @@ fn compile_abi_method( .parameters .iter() .map(|param| { - convert_resolved_typeid(context, ¶m.type_id, ¶m.type_span) + convert_resolved_typeid(type_engine, context, ¶m.type_id, ¶m.type_span) .map(|ty| (param.name.as_str().into(), ty, param.name.span())) }) .collect::, CompileError>>()?; compile_fn_with_args( + type_engine, context, md_mgr, module, diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index d328bf69120..8eceb400b27 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -3,6 +3,7 @@ use crate::{ language::ty, metadata::MetadataManager, semantic_analysis::*, + PartialEqWithTypeEngine, TypeEngine, }; use super::{convert::convert_literal_to_constant, function::FnCompiler, types::*}; @@ -19,11 +20,12 @@ use sway_types::{ident::Ident, span::Spanned}; use sway_utils::mapped_stack::MappedStack; pub(crate) struct LookupEnv<'a> { + pub(crate) type_engine: &'a TypeEngine, pub(crate) context: &'a mut Context, pub(crate) md_mgr: &'a mut MetadataManager, pub(crate) module: Module, pub(crate) module_ns: Option<&'a namespace::Module>, - pub(crate) function_compiler: Option<&'a FnCompiler>, + pub(crate) function_compiler: Option<&'a FnCompiler<'a>>, pub(crate) lookup: fn(&mut LookupEnv, &Ident) -> Result, CompileError>, } @@ -97,6 +99,7 @@ pub(crate) fn compile_const_decl( }; if let Some((name, value)) = decl_name_value { let const_val = compile_constant_expression( + env.type_engine, env.context, env.md_mgr, env.module, @@ -116,6 +119,7 @@ pub(crate) fn compile_const_decl( } pub(super) fn compile_constant_expression( + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -126,6 +130,7 @@ pub(super) fn compile_constant_expression( let span_id_idx = md_mgr.span_to_md(context, &const_expr.span); let constant_evaluated = compile_constant_expression_to_constant( + type_engine, context, md_mgr, module, @@ -137,6 +142,7 @@ pub(super) fn compile_constant_expression( } pub(crate) fn compile_constant_expression_to_constant( + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -145,6 +151,7 @@ pub(crate) fn compile_constant_expression_to_constant( const_expr: &ty::TyExpression, ) -> Result { let lookup = &mut LookupEnv { + type_engine, context, md_mgr, module, @@ -244,9 +251,10 @@ fn const_eval_typed_expr( // We couldn't evaluate all fields to a constant. return Ok(None); } - get_aggregate_for_types(lookup.context, &field_typs).map_or(None, |aggregate| { - Some(Constant::new_struct(&aggregate, field_vals)) - }) + get_aggregate_for_types(lookup.type_engine, lookup.context, &field_typs) + .map_or(None, |aggregate| { + Some(Constant::new_struct(&aggregate, field_vals)) + }) } ty::TyExpressionVariant::Tuple { fields } => { let (mut field_typs, mut field_vals): (Vec<_>, Vec<_>) = (vec![], vec![]); @@ -261,9 +269,10 @@ fn const_eval_typed_expr( // We couldn't evaluate all fields to a constant. return Ok(None); } - create_tuple_aggregate(lookup.context, field_typs).map_or(None, |aggregate| { - Some(Constant::new_struct(&aggregate, field_vals)) - }) + create_tuple_aggregate(lookup.type_engine, lookup.context, field_typs) + .map_or(None, |aggregate| { + Some(Constant::new_struct(&aggregate, field_vals)) + }) } ty::TyExpressionVariant::Array { contents } => { let (mut element_typs, mut element_vals): (Vec<_>, Vec<_>) = (vec![], vec![]); @@ -281,13 +290,16 @@ fn const_eval_typed_expr( let mut element_iter = element_typs.iter(); let element_type_id = *element_iter.next().unwrap(); if !element_iter.all(|tid| { - crate::type_system::look_up_type_id(*tid) - == crate::type_system::look_up_type_id(element_type_id) + lookup.type_engine.look_up_type_id(*tid).eq( + &lookup.type_engine.look_up_type_id(element_type_id), + lookup.type_engine, + ) }) { // This shouldn't happen if the type checker did its job. return Ok(None); } create_array_aggregate( + lookup.type_engine, lookup.context, element_type_id, element_typs.len().try_into().unwrap(), @@ -302,7 +314,11 @@ fn const_eval_typed_expr( contents, .. } => { - let aggregate = create_enum_aggregate(lookup.context, enum_decl.variants.clone()); + let aggregate = create_enum_aggregate( + lookup.type_engine, + lookup.context, + enum_decl.variants.clone(), + ); if let Ok(aggregate) = aggregate { let tag_value = Constant::new_uint(64, *tag as u64); let mut fields: Vec = vec![tag_value]; @@ -333,11 +349,15 @@ fn const_eval_typed_expr( let field_kind = ty::ProjectionKind::StructField { name: field_to_access.name.clone(), }; - get_struct_name_field_index_and_type(*resolved_type_of_parent, field_kind) - .and_then(|(_struct_name, field_idx_and_type_opt)| { - field_idx_and_type_opt.map(|(field_idx, _field_type)| field_idx) - }) - .and_then(|field_idx| fields.get(field_idx as usize).cloned()) + get_struct_name_field_index_and_type( + lookup.type_engine, + *resolved_type_of_parent, + field_kind, + ) + .and_then(|(_struct_name, field_idx_and_type_opt)| { + field_idx_and_type_opt.map(|(field_idx, _field_type)| field_idx) + }) + .and_then(|field_idx| fields.get(field_idx as usize).cloned()) } _ => None, }, diff --git a/sway-core/src/ir_generation/convert.rs b/sway-core/src/ir_generation/convert.rs index 9ff697a633f..92d3cc5e490 100644 --- a/sway-core/src/ir_generation/convert.rs +++ b/sway-core/src/ir_generation/convert.rs @@ -1,6 +1,7 @@ use crate::{ language::Literal, - type_system::{to_typeinfo, TypeId, TypeInfo}, + type_system::{TypeId, TypeInfo}, + TypeEngine, }; use super::types::{create_enum_aggregate, create_tuple_aggregate}; @@ -43,6 +44,7 @@ pub(super) fn convert_literal_to_constant(ast_literal: &Literal) -> Constant { } pub(super) fn convert_resolved_typeid( + type_engine: &TypeEngine, context: &mut Context, ast_type: &TypeId, span: &Span, @@ -50,23 +52,27 @@ pub(super) fn convert_resolved_typeid( // There's probably a better way to convert TypeError to String, but... we'll use something // other than String eventually? IrError? convert_resolved_type( + type_engine, context, - &to_typeinfo(*ast_type, span) + &type_engine + .to_typeinfo(*ast_type, span) .map_err(|ty_err| CompileError::InternalOwned(format!("{ty_err:?}"), span.clone()))?, span, ) } pub(super) fn convert_resolved_typeid_no_span( + type_engine: &TypeEngine, context: &mut Context, ast_type: &TypeId, ) -> Result { let msg = "unknown source location"; let span = crate::span::Span::from_string(msg.to_string()); - convert_resolved_typeid(context, ast_type, &span) + convert_resolved_typeid(type_engine, context, ast_type, &span) } fn convert_resolved_type( + type_engine: &TypeEngine, context: &mut Context, ast_type: &TypeInfo, span: &Span, @@ -89,6 +95,7 @@ fn convert_resolved_type( TypeInfo::B256 => Type::B256, TypeInfo::Str(n) => Type::String(*n), TypeInfo::Struct { fields, .. } => super::types::get_aggregate_for_types( + type_engine, context, fields .iter() @@ -98,10 +105,10 @@ fn convert_resolved_type( ) .map(Type::Struct)?, TypeInfo::Enum { variant_types, .. } => { - create_enum_aggregate(context, variant_types.clone()).map(Type::Struct)? + create_enum_aggregate(type_engine, context, variant_types.clone()).map(Type::Struct)? } TypeInfo::Array(elem_type_id, count, _) => { - let elem_type = convert_resolved_typeid(context, elem_type_id, span)?; + let elem_type = convert_resolved_typeid(type_engine, context, elem_type_id, span)?; Type::Array(Aggregate::new_array(context, elem_type, *count as u64)) } TypeInfo::Tuple(fields) => { @@ -112,7 +119,7 @@ fn convert_resolved_type( Type::Unit } else { let new_fields = fields.iter().map(|x| x.type_id).collect(); - create_tuple_aggregate(context, new_fields).map(Type::Struct)? + create_tuple_aggregate(type_engine, context, new_fields).map(Type::Struct)? } } TypeInfo::RawUntypedPtr => Type::Uint(64), diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index dbb1201cf44..7dc4a3bb409 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -14,7 +14,8 @@ use crate::{ }, language::{ty, *}, metadata::MetadataManager, - type_system::{look_up_type_id, to_typeinfo, LogId, TypeId, TypeInfo}, + type_system::{LogId, TypeId, TypeInfo}, + PartialEqWithTypeEngine, TypeEngine, }; use declaration_engine::de_get_function; use sway_ast::intrinsics::Intrinsic; @@ -29,7 +30,8 @@ use sway_types::{ use std::collections::HashMap; -pub(crate) struct FnCompiler { +pub(crate) struct FnCompiler<'te> { + type_engine: &'te TypeEngine, module: Module, pub(super) function: Function, pub(super) current_block: Block, @@ -43,8 +45,9 @@ pub(crate) struct FnCompiler { logged_types_map: HashMap, } -impl FnCompiler { +impl<'te> FnCompiler<'te> { pub(super) fn new( + type_engine: &'te TypeEngine, context: &mut Context, module: Module, function: Function, @@ -57,6 +60,7 @@ impl FnCompiler { .map(|(name, _value)| name.clone()), ); FnCompiler { + type_engine, module, function, current_block: function.get_entry_block(context), @@ -153,7 +157,7 @@ impl FnCompiler { } ty::TyDeclaration::EnumDeclaration(decl_id) => { let ted = declaration_engine::de_get_enum(decl_id, &ast_node.span)?; - create_enum_aggregate(context, ted.variants).map(|_| ())?; + create_enum_aggregate(self.type_engine, context, ted.variants).map(|_| ())?; Ok(None) } ty::TyDeclaration::ImplTrait(_) => { @@ -444,7 +448,12 @@ impl FnCompiler { Intrinsic::SizeOfVal => { let exp = arguments[0].clone(); // Compile the expression in case of side-effects but ignore its value. - let ir_type = convert_resolved_typeid(context, &exp.return_type, &exp.span)?; + let ir_type = convert_resolved_typeid( + self.type_engine, + context, + &exp.return_type, + &exp.span, + )?; self.compile_expression(context, md_mgr, exp)?; Ok(Constant::get_uint( context, @@ -454,7 +463,8 @@ impl FnCompiler { } Intrinsic::SizeOfType => { let targ = type_arguments[0].clone(); - let ir_type = convert_resolved_typeid(context, &targ.type_id, &targ.span)?; + let ir_type = + convert_resolved_typeid(self.type_engine, context, &targ.type_id, &targ.span)?; Ok(Constant::get_uint( context, 64, @@ -463,7 +473,8 @@ impl FnCompiler { } Intrinsic::IsReferenceType => { let targ = type_arguments[0].clone(); - let ir_type = convert_resolved_typeid(context, &targ.type_id, &targ.span)?; + let ir_type = + convert_resolved_typeid(self.type_engine, context, &targ.type_id, &targ.span)?; Ok(Constant::get_bool(context, !ir_type.is_copy_type())) } Intrinsic::GetStorageKey => { @@ -491,6 +502,7 @@ impl FnCompiler { // The tx field ID has to be a compile-time constant because it becomes an // immediate let tx_field_id_constant = compile_constant_expression_to_constant( + self.type_engine, context, md_mgr, self.module, @@ -511,8 +523,12 @@ impl FnCompiler { // Get the target type from the type argument provided let target_type = type_arguments[0].clone(); - let target_ir_type = - convert_resolved_typeid(context, &target_type.type_id, &target_type.span)?; + let target_ir_type = convert_resolved_typeid( + self.type_engine, + context, + &target_type.type_id, + &target_type.span, + )?; let span_md_idx = md_mgr.span_to_md(context, &span); @@ -561,7 +577,7 @@ impl FnCompiler { let val_exp = arguments[1].clone(); // Validate that the val_exp is of the right type. We couldn't do it // earlier during type checking as the type arguments may not have been resolved. - let val_ty = to_typeinfo(val_exp.return_type, &span)?; + let val_ty = self.type_engine.to_typeinfo(val_exp.return_type, &span)?; if !val_ty.is_copy_type() { return Err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), @@ -584,8 +600,8 @@ impl FnCompiler { let val_exp = arguments[1].clone(); // Validate that the val_exp is of the right type. We couldn't do it // earlier during type checking as the type arguments may not have been resolved. - let val_ty = to_typeinfo(val_exp.return_type, &span)?; - if val_ty != TypeInfo::RawUntypedPtr { + let val_ty = self.type_engine.to_typeinfo(val_exp.return_type, &span)?; + if !val_ty.eq(&TypeInfo::RawUntypedPtr, self.type_engine) { return Err(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span, @@ -685,7 +701,8 @@ impl FnCompiler { }; let len = type_arguments[0].clone(); - let ir_type = convert_resolved_typeid(context, &len.type_id, &len.span)?; + let ir_type = + convert_resolved_typeid(self.type_engine, context, &len.type_id, &len.span)?; let len_value = Constant::get_uint(context, 64, ir_type_size_in_bytes(context, &ir_type)); @@ -1026,7 +1043,7 @@ impl FnCompiler { .add_metadatum(context, span_md_idx), }; - let return_type = convert_resolved_typeid_no_span(context, &return_type)?; + let return_type = convert_resolved_typeid_no_span(self.type_engine, context, &return_type)?; // Insert the contract_call instruction Ok(self @@ -1090,6 +1107,7 @@ impl FnCompiler { }; let is_entry = false; let new_func = compile_function( + self.type_engine, context, md_mgr, self.module, @@ -1241,7 +1259,12 @@ impl FnCompiler { variant: ty::TyEnumVariant, ) -> Result { // retrieve the aggregate info for the enum - let enum_aggregate = match convert_resolved_typeid(context, &exp.return_type, &exp.span)? { + let enum_aggregate = match convert_resolved_typeid( + self.type_engine, + context, + &exp.return_type, + &exp.span, + )? { Type::Struct(aggregate) => aggregate, _ => { return Err(CompileError::Internal( @@ -1267,7 +1290,12 @@ impl FnCompiler { exp: Box, ) -> Result { let tag_span_md_idx = md_mgr.span_to_md(context, &exp.span); - let enum_aggregate = match convert_resolved_typeid(context, &exp.return_type, &exp.span)? { + let enum_aggregate = match convert_resolved_typeid( + self.type_engine, + context, + &exp.return_type, + &exp.span, + )? { Type::Struct(aggregate) => aggregate, _ => { return Err(CompileError::Internal("Expected enum type here.", exp.span)); @@ -1376,7 +1404,10 @@ impl FnCompiler { .add_metadatum(context, span_md_idx); let fn_param = self.current_fn_param.as_ref(); let is_ref_primitive = fn_param.is_some() - && look_up_type_id(fn_param.unwrap().type_id).is_copy_type() + && self + .type_engine + .look_up_type_id(fn_param.unwrap().type_id) + .is_copy_type() && fn_param.unwrap().is_reference && fn_param.unwrap().is_mutable; Ok(if ptr.is_aggregate_ptr(context) || is_ref_primitive { @@ -1424,16 +1455,20 @@ impl FnCompiler { // Nothing to do for an abi cast declarations. The address specified in them is already // provided in each contract call node in the AST. if matches!( - &to_typeinfo(body.return_type, &body.span).map_err(|ty_err| { - CompileError::InternalOwned(format!("{:?}", ty_err), body.span.clone()) - })?, + &self + .type_engine + .to_typeinfo(body.return_type, &body.span) + .map_err(|ty_err| { + CompileError::InternalOwned(format!("{:?}", ty_err), body.span.clone()) + })?, TypeInfo::ContractCaller { .. } ) { return Ok(None); } // Grab these before we move body into compilation. - let return_type = convert_resolved_typeid(context, &body.return_type, &body.span)?; + let return_type = + convert_resolved_typeid(self.type_engine, context, &body.return_type, &body.span)?; // We must compile the RHS before checking for shadowing, as it will still be in the // previous scope. @@ -1480,10 +1515,18 @@ impl FnCompiler { // This is local to the function, so we add it to the locals, rather than the module // globals like other const decls. let ty::TyConstantDeclaration { name, value, .. } = ast_const_decl; - let const_expr_val = - compile_constant_expression(context, md_mgr, self.module, None, Some(self), &value)?; + let const_expr_val = compile_constant_expression( + self.type_engine, + context, + md_mgr, + self.module, + None, + Some(self), + &value, + )?; let local_name = self.lexical_map.insert(name.as_str().to_owned()); - let return_type = convert_resolved_typeid(context, &value.return_type, &value.span)?; + let return_type = + convert_resolved_typeid(self.type_engine, context, &value.return_type, &value.span)?; // We compile consts the same as vars are compiled. This is because ASM generation // cannot handle @@ -1564,6 +1607,7 @@ impl FnCompiler { // field indices. The struct type from the previous iteration is used to determine the // field type for the current iteration. let field_idcs = get_indices_for_struct_access( + self.type_engine, ast_reassignment.lhs_type, &ast_reassignment.lhs_indices, )?; @@ -1610,6 +1654,7 @@ impl FnCompiler { // Get the type of the access which can be a subfield let access_type = convert_resolved_typeid_no_span( + self.type_engine, context, &fields.last().expect("guaranteed by grammar").type_id, )?; @@ -1617,7 +1662,7 @@ impl FnCompiler { // Get the list of indices used to access the storage field. This will be empty // if the storage field type is not a struct. let base_type = fields[0].type_id; - let field_idcs = get_indices_for_struct_access(base_type, &fields[1..])?; + let field_idcs = get_indices_for_struct_access(self.type_engine, base_type, &fields[1..])?; // Do the actual work. This is a recursive function because we want to drill down // to store each primitive type in the storage field in its own storage slot. @@ -1646,7 +1691,7 @@ impl FnCompiler { // we'll just use Unit. Type::Unit } else { - convert_resolved_typeid_no_span(context, &contents[0].return_type)? + convert_resolved_typeid_no_span(self.type_engine, context, &contents[0].return_type)? }; let aggregate = Aggregate::new_array(context, elem_type, contents.len() as u64); @@ -1725,6 +1770,7 @@ impl FnCompiler { value: ConstantValue::Uint(constant_value), .. }) = compile_constant_expression_to_constant( + self.type_engine, context, md_mgr, self.module, @@ -1782,7 +1828,7 @@ impl FnCompiler { } // Start with a temporary empty struct and then fill in the values. - let aggregate = get_aggregate_for_types(context, &field_types)?; + let aggregate = get_aggregate_for_types(self.type_engine, context, &field_types)?; let temp_name = self.lexical_map.insert_anon(); let struct_ptr = self .function @@ -1841,7 +1887,11 @@ impl FnCompiler { let field_kind = ty::ProjectionKind::StructField { name: ast_field.name.clone(), }; - let field_idx = match get_struct_name_field_index_and_type(struct_type_id, field_kind) { + let field_idx = match get_struct_name_field_index_and_type( + self.type_engine, + struct_type_id, + field_kind, + ) { None => Err(CompileError::Internal( "Unknown struct in field expression.", ast_field.span, @@ -1880,7 +1930,7 @@ impl FnCompiler { // we could potentially use the wrong aggregate with the same name, different module... // dunno. let span_md_idx = md_mgr.span_to_md(context, &enum_decl.span); - let aggregate = create_enum_aggregate(context, enum_decl.variants)?; + let aggregate = create_enum_aggregate(self.type_engine, context, enum_decl.variants)?; let tag_value = Constant::get_uint(context, 64, tag as u64).add_metadatum(context, span_md_idx); @@ -1942,7 +1992,11 @@ impl FnCompiler { let mut init_values = Vec::with_capacity(fields.len()); let mut init_types = Vec::with_capacity(fields.len()); for field_expr in fields { - let init_type = convert_resolved_typeid_no_span(context, &field_expr.return_type)?; + let init_type = convert_resolved_typeid_no_span( + self.type_engine, + context, + &field_expr.return_type, + )?; let init_value = self.compile_expression(context, md_mgr, field_expr)?; if init_value.is_diverging(context) { return Ok(init_value); @@ -1988,7 +2042,9 @@ impl FnCompiler { span: Span, ) -> Result { let tuple_value = self.compile_expression(context, md_mgr, tuple)?; - if let Type::Struct(aggregate) = convert_resolved_typeid(context, &tuple_type, &span)? { + if let Type::Struct(aggregate) = + convert_resolved_typeid(self.type_engine, context, &tuple_type, &span)? + { let span_md_idx = md_mgr.span_to_md(context, &span); Ok(self .current_block @@ -2013,6 +2069,7 @@ impl FnCompiler { ) -> Result { // Get the type of the access which can be a subfield let access_type = convert_resolved_typeid_no_span( + self.type_engine, context, &fields.last().expect("guaranteed by grammar").type_id, )?; @@ -2021,7 +2078,7 @@ impl FnCompiler { // if the storage field type is not a struct. // FIXME: shouldn't have to extract the first field like this. let base_type = fields[0].type_id; - let field_idcs = get_indices_for_struct_access(base_type, &fields[1..])?; + let field_idcs = get_indices_for_struct_access(self.type_engine, base_type, &fields[1..])?; // Do the actual work. This is a recursive function because we want to drill down // to load each primitive type in the storage field in its own storage slot. @@ -2076,7 +2133,7 @@ impl FnCompiler { let returns = returns .as_ref() .map(|(_, asm_reg_span)| Ident::new(asm_reg_span.clone())); - let return_type = convert_resolved_typeid_no_span(context, &return_type)?; + let return_type = convert_resolved_typeid_no_span(self.type_engine, context, &return_type)?; Ok(self .current_block .ins(context) diff --git a/sway-core/src/ir_generation/types.rs b/sway-core/src/ir_generation/types.rs index 9a55f168d55..4818326bf75 100644 --- a/sway-core/src/ir_generation/types.rs +++ b/sway-core/src/ir_generation/types.rs @@ -1,6 +1,7 @@ use crate::{ language::ty, - type_system::{to_typeinfo, TypeId, TypeInfo}, + type_system::{TypeId, TypeInfo}, + TypeEngine, }; use super::convert::convert_resolved_typeid_no_span; @@ -10,6 +11,7 @@ use sway_ir::{Aggregate, Context, Type}; use sway_types::span::Spanned; pub(super) fn create_enum_aggregate( + type_engine: &TypeEngine, context: &mut Context, variants: Vec, ) -> Result { @@ -17,7 +19,7 @@ pub(super) fn create_enum_aggregate( // getting one here anyway. They don't need to be a tagged union either. let field_types: Vec<_> = variants .into_iter() - .map(|tev| convert_resolved_typeid_no_span(context, &tev.type_id)) + .map(|tev| convert_resolved_typeid_no_span(type_engine, context, &tev.type_id)) .collect::, CompileError>>()?; // Enums where all the variants are unit types don't really need the union. Only a tag is @@ -32,42 +34,48 @@ pub(super) fn create_enum_aggregate( } pub(super) fn create_tuple_aggregate( + type_engine: &TypeEngine, context: &mut Context, fields: Vec, ) -> Result { let field_types = fields .into_iter() - .map(|ty_id| convert_resolved_typeid_no_span(context, &ty_id)) + .map(|ty_id| convert_resolved_typeid_no_span(type_engine, context, &ty_id)) .collect::, CompileError>>()?; Ok(Aggregate::new_struct(context, field_types)) } pub(super) fn create_array_aggregate( + type_engine: &TypeEngine, context: &mut Context, element_type_id: TypeId, count: u64, ) -> Result { - let element_type = convert_resolved_typeid_no_span(context, &element_type_id)?; + let element_type = convert_resolved_typeid_no_span(type_engine, context, &element_type_id)?; Ok(Aggregate::new_array(context, element_type, count)) } pub(super) fn get_aggregate_for_types( + type_engine: &TypeEngine, context: &mut Context, type_ids: &[TypeId], ) -> Result { let types = type_ids .iter() - .map(|ty_id| convert_resolved_typeid_no_span(context, ty_id)) + .map(|ty_id| convert_resolved_typeid_no_span(type_engine, context, ty_id)) .collect::, CompileError>>()?; Ok(Aggregate::new_struct(context, types)) } pub(super) fn get_struct_name_field_index_and_type( + type_engine: &TypeEngine, field_type: TypeId, field_kind: ty::ProjectionKind, ) -> Option<(String, Option<(u64, TypeId)>)> { - let ty_info = to_typeinfo(field_type, &field_kind.span()).ok()?; + let ty_info = type_engine + .to_typeinfo(field_type, &field_kind.span()) + .ok()?; match (ty_info, field_kind) { ( TypeInfo::Struct { name, fields, .. }, @@ -116,9 +124,10 @@ use ty::TyStorageReassignDescriptor; impl_typed_named_field_for!(TyStorageAccessDescriptor); impl_typed_named_field_for!(TyStorageReassignDescriptor); -pub(super) fn get_indices_for_struct_access( +pub(super) fn get_indices_for_struct_access( + type_engine: &TypeEngine, base_type: TypeId, - fields: &[F], + fields: &[impl TypedNamedField], ) -> Result, CompileError> { fields .iter() @@ -126,7 +135,7 @@ pub(super) fn get_indices_for_struct_access( (Vec::new(), base_type), |(mut fld_idcs, prev_type_id), field| { let field_kind = field.get_field_kind(); - let ty_info = match to_typeinfo(prev_type_id, &field_kind.span()) { + let ty_info = match type_engine.to_typeinfo(prev_type_id, &field_kind.span()) { Ok(ty_info) => ty_info, Err(error) => { return Err(CompileError::InternalOwned( diff --git a/sway-core/src/language/literal.rs b/sway-core/src/language/literal.rs index de39c5ba91c..429cd099dae 100644 --- a/sway-core/src/language/literal.rs +++ b/sway-core/src/language/literal.rs @@ -121,21 +121,22 @@ impl Literal { #[allow(clippy::wildcard_in_or_patterns)] pub(crate) fn handle_parse_int_error( + type_engine: &TypeEngine, e: ParseIntError, ty: TypeInfo, span: sway_types::Span, ) -> CompileError { match e.kind() { IntErrorKind::PosOverflow => CompileError::IntegerTooLarge { - ty: ty.to_string(), + ty: type_engine.help_out(ty).to_string(), span, }, IntErrorKind::NegOverflow => CompileError::IntegerTooSmall { - ty: ty.to_string(), + ty: type_engine.help_out(ty).to_string(), span, }, IntErrorKind::InvalidDigit => CompileError::IntegerContainsInvalidDigit { - ty: ty.to_string(), + ty: type_engine.help_out(ty).to_string(), span, }, IntErrorKind::Zero | IntErrorKind::Empty | _ => { diff --git a/sway-core/src/language/parsed/declaration/function.rs b/sway-core/src/language/parsed/declaration/function.rs index 8d746c7b5b4..0a69da05fc9 100644 --- a/sway-core/src/language/parsed/declaration/function.rs +++ b/sway-core/src/language/parsed/declaration/function.rs @@ -19,7 +19,7 @@ pub struct FunctionDeclaration { pub return_type_span: Span, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct FunctionParameter { pub name: Ident, pub is_reference: bool, @@ -28,3 +28,15 @@ pub struct FunctionParameter { pub type_info: TypeInfo, pub type_span: Span, } + +impl EqWithTypeEngine for FunctionParameter {} +impl PartialEqWithTypeEngine for FunctionParameter { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.name == rhs.name + && self.is_reference == rhs.is_reference + && self.is_mutable == rhs.is_mutable + && self.mutability_span == rhs.mutability_span + && self.type_info.eq(&rhs.type_info, type_engine) + && self.type_span == rhs.type_span + } +} diff --git a/sway-core/src/language/ty/ast_node.rs b/sway-core/src/language/ty/ast_node.rs index d13f03a94c4..4229d03c357 100644 --- a/sway-core/src/language/ty/ast_node.rs +++ b/sway-core/src/language/ty/ast_node.rs @@ -1,6 +1,5 @@ -use std::fmt; +use std::fmt::{self, Debug}; -use derivative::Derivative; use sway_types::{Ident, Span}; use crate::{ @@ -15,59 +14,75 @@ pub trait GetDeclIdent { fn get_decl_ident(&self) -> Option; } -#[derive(Clone, Debug, Eq, Derivative)] -#[derivative(PartialEq)] +#[derive(Clone, Debug)] pub struct TyAstNode { pub content: TyAstNodeContent, - #[derivative(PartialEq = "ignore")] pub(crate) span: Span, } -impl fmt::Display for TyAstNode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl EqWithTypeEngine for TyAstNode {} +impl PartialEqWithTypeEngine for TyAstNode { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.content.eq(&rhs.content, type_engine) + } +} + +impl DisplayWithTypeEngine for TyAstNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { use TyAstNodeContent::*; - let text = match &self.content { - Declaration(ref typed_decl) => typed_decl.to_string(), - Expression(exp) => exp.to_string(), - ImplicitReturnExpression(exp) => format!("return {}", exp), - SideEffect => "".into(), - }; - f.write_str(&text) + match &self.content { + Declaration(typed_decl) => DisplayWithTypeEngine::fmt(typed_decl, f, type_engine), + Expression(exp) => DisplayWithTypeEngine::fmt(exp, f, type_engine), + ImplicitReturnExpression(exp) => write!(f, "return {}", type_engine.help_out(exp)), + SideEffect => f.write_str(""), + } } } impl CopyTypes for TyAstNode { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { match self.content { - TyAstNodeContent::ImplicitReturnExpression(ref mut exp) => exp.copy_types(type_mapping), - TyAstNodeContent::Declaration(ref mut decl) => decl.copy_types(type_mapping), - TyAstNodeContent::Expression(ref mut expr) => expr.copy_types(type_mapping), + TyAstNodeContent::ImplicitReturnExpression(ref mut exp) => { + exp.copy_types(type_mapping, type_engine) + } + TyAstNodeContent::Declaration(ref mut decl) => { + decl.copy_types(type_mapping, type_engine) + } + TyAstNodeContent::Expression(ref mut expr) => { + expr.copy_types(type_mapping, type_engine) + } TyAstNodeContent::SideEffect => (), } } } impl ReplaceSelfType for TyAstNode { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { match self.content { TyAstNodeContent::ImplicitReturnExpression(ref mut exp) => { - exp.replace_self_type(self_type) + exp.replace_self_type(type_engine, self_type) + } + TyAstNodeContent::Declaration(ref mut decl) => { + decl.replace_self_type(type_engine, self_type) + } + TyAstNodeContent::Expression(ref mut expr) => { + expr.replace_self_type(type_engine, self_type) } - TyAstNodeContent::Declaration(ref mut decl) => decl.replace_self_type(self_type), - TyAstNodeContent::Expression(ref mut expr) => expr.replace_self_type(self_type), TyAstNodeContent::SideEffect => (), } } } impl ReplaceDecls for TyAstNode { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping) { + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { match self.content { TyAstNodeContent::ImplicitReturnExpression(ref mut exp) => { - exp.replace_decls(decl_mapping) + exp.replace_decls(decl_mapping, type_engine) } TyAstNodeContent::Declaration(_) => {} - TyAstNodeContent::Expression(ref mut expr) => expr.replace_decls(decl_mapping), + TyAstNodeContent::Expression(ref mut expr) => { + expr.replace_decls(decl_mapping, type_engine) + } TyAstNodeContent::SideEffect => (), } } @@ -165,22 +180,22 @@ impl TyAstNode { } } - pub(crate) fn type_info(&self) -> TypeInfo { + pub(crate) fn type_info(&self, type_engine: &TypeEngine) -> TypeInfo { // return statement should be () match &self.content { TyAstNodeContent::Declaration(_) => TypeInfo::Tuple(Vec::new()), TyAstNodeContent::Expression(TyExpression { return_type, .. }) => { - look_up_type_id(*return_type) + type_engine.look_up_type_id(*return_type) } TyAstNodeContent::ImplicitReturnExpression(TyExpression { return_type, .. }) => { - look_up_type_id(*return_type) + type_engine.look_up_type_id(*return_type) } TyAstNodeContent::SideEffect => TypeInfo::Tuple(Vec::new()), } } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum TyAstNodeContent { Declaration(TyDeclaration), Expression(TyExpression), @@ -189,6 +204,21 @@ pub enum TyAstNodeContent { SideEffect, } +impl EqWithTypeEngine for TyAstNodeContent {} +impl PartialEqWithTypeEngine for TyAstNodeContent { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + match (self, rhs) { + (Self::Declaration(x), Self::Declaration(y)) => x.eq(y, type_engine), + (Self::Expression(x), Self::Expression(y)) => x.eq(y, type_engine), + (Self::ImplicitReturnExpression(x), Self::ImplicitReturnExpression(y)) => { + x.eq(y, type_engine) + } + (Self::SideEffect, Self::SideEffect) => true, + _ => false, + } + } +} + impl CollectTypesMetadata for TyAstNodeContent { fn collect_types_metadata( &self, diff --git a/sway-core/src/language/ty/code_block.rs b/sway-core/src/language/ty/code_block.rs index 69593af7857..b1f46032ece 100644 --- a/sway-core/src/language/ty/code_block.rs +++ b/sway-core/src/language/ty/code_block.rs @@ -5,32 +5,39 @@ use crate::{ types::DeterministicallyAborts, }; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug)] pub struct TyCodeBlock { pub contents: Vec, } +impl EqWithTypeEngine for TyCodeBlock {} +impl PartialEqWithTypeEngine for TyCodeBlock { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.contents.eq(&rhs.contents, type_engine) + } +} + impl CopyTypes for TyCodeBlock { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { self.contents .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); } } impl ReplaceSelfType for TyCodeBlock { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { self.contents .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); } } impl ReplaceDecls for TyCodeBlock { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping) { + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { self.contents .iter_mut() - .for_each(|x| x.replace_decls(decl_mapping)); + .for_each(|x| x.replace_decls(decl_mapping, type_engine)); } } diff --git a/sway-core/src/language/ty/declaration/abi.rs b/sway-core/src/language/ty/declaration/abi.rs index 588e8949726..31663437251 100644 --- a/sway-core/src/language/ty/declaration/abi.rs +++ b/sway-core/src/language/ty/declaration/abi.rs @@ -1,29 +1,36 @@ -use derivative::Derivative; use sway_types::{Ident, Span}; use crate::{declaration_engine::DeclarationId, transform, type_system::*}; /// A [TyAbiDeclaration] contains the type-checked version of the parse tree's `AbiDeclaration`. -#[derive(Clone, Debug, Derivative)] -#[derivative(PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct TyAbiDeclaration { /// The name of the abi trait (also known as a "contract trait") pub name: Ident, /// The methods a contract is required to implement in order opt in to this interface pub interface_surface: Vec, pub methods: Vec, - #[derivative(PartialEq = "ignore")] - #[derivative(Eq(bound = ""))] pub span: Span, pub attributes: transform::AttributesMap, } +impl EqWithTypeEngine for TyAbiDeclaration {} +impl PartialEqWithTypeEngine for TyAbiDeclaration { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.name == rhs.name + && self.interface_surface.eq(&rhs.interface_surface, type_engine) + && self.methods.eq(&rhs.methods, type_engine) + // span ignored + && self.attributes == rhs.attributes + } +} + impl CreateTypeId for TyAbiDeclaration { - fn create_type_id(&self) -> TypeId { + fn create_type_id(&self, type_engine: &TypeEngine) -> TypeId { let ty = TypeInfo::ContractCaller { abi_name: AbiName::Known(self.name.clone().into()), address: None, }; - insert_type(ty) + type_engine.insert_type(ty) } } diff --git a/sway-core/src/language/ty/declaration/constant.rs b/sway-core/src/language/ty/declaration/constant.rs index 9ba75e79a3e..d45e756d95e 100644 --- a/sway-core/src/language/ty/declaration/constant.rs +++ b/sway-core/src/language/ty/declaration/constant.rs @@ -2,10 +2,10 @@ use sway_types::{Ident, Span}; use crate::{ language::{ty::*, Visibility}, - transform, + transform, EqWithTypeEngine, PartialEqWithTypeEngine, }; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct TyConstantDeclaration { pub name: Ident, pub value: TyExpression, @@ -13,3 +13,14 @@ pub struct TyConstantDeclaration { pub attributes: transform::AttributesMap, pub span: Span, } + +impl EqWithTypeEngine for TyConstantDeclaration {} +impl PartialEqWithTypeEngine for TyConstantDeclaration { + fn eq(&self, rhs: &Self, type_engine: &crate::TypeEngine) -> bool { + self.name == rhs.name + && self.value.eq(&rhs.value, type_engine) + && self.visibility == rhs.visibility + && self.attributes == rhs.attributes + && self.span == rhs.span + } +} diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index 0e430015749..cf3298df4a3 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -1,5 +1,3 @@ -use std::fmt; - use sway_error::error::CompileError; use sway_types::{Ident, Span, Spanned}; @@ -10,7 +8,7 @@ use crate::{ type_system::*, }; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum TyDeclaration { VariableDeclaration(Box), ConstantDeclaration(DeclarationId), @@ -27,16 +25,45 @@ pub enum TyDeclaration { StorageDeclaration(DeclarationId), } +impl EqWithTypeEngine for TyDeclaration {} +impl PartialEqWithTypeEngine for TyDeclaration { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + match (self, rhs) { + (Self::VariableDeclaration(x), Self::VariableDeclaration(y)) => x.eq(y, type_engine), + (Self::ConstantDeclaration(x), Self::ConstantDeclaration(y)) => x.eq(y, type_engine), + (Self::FunctionDeclaration(x), Self::FunctionDeclaration(y)) => x.eq(y, type_engine), + (Self::TraitDeclaration(x), Self::TraitDeclaration(y)) => x.eq(y, type_engine), + (Self::StructDeclaration(x), Self::StructDeclaration(y)) => x.eq(y, type_engine), + (Self::EnumDeclaration(x), Self::EnumDeclaration(y)) => x.eq(y, type_engine), + (Self::ImplTrait(x), Self::ImplTrait(y)) => x.eq(y, type_engine), + (Self::AbiDeclaration(x), Self::AbiDeclaration(y)) => x.eq(y, type_engine), + (Self::StorageDeclaration(x), Self::StorageDeclaration(y)) => x.eq(y, type_engine), + ( + Self::GenericTypeForFunctionScope { + name: xn, + type_id: xti, + }, + Self::GenericTypeForFunctionScope { + name: yn, + type_id: yti, + }, + ) => xn == yn && xti == yti, + (Self::ErrorRecovery(x), Self::ErrorRecovery(y)) => x == y, + _ => false, + } + } +} + impl CopyTypes for TyDeclaration { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { use TyDeclaration::*; match self { - VariableDeclaration(ref mut var_decl) => var_decl.copy_types(type_mapping), - FunctionDeclaration(ref mut decl_id) => decl_id.copy_types(type_mapping), - TraitDeclaration(ref mut decl_id) => decl_id.copy_types(type_mapping), - StructDeclaration(ref mut decl_id) => decl_id.copy_types(type_mapping), - EnumDeclaration(ref mut decl_id) => decl_id.copy_types(type_mapping), - ImplTrait(decl_id) => decl_id.copy_types(type_mapping), + VariableDeclaration(ref mut var_decl) => var_decl.copy_types(type_mapping, type_engine), + FunctionDeclaration(ref mut decl_id) => decl_id.copy_types(type_mapping, type_engine), + TraitDeclaration(ref mut decl_id) => decl_id.copy_types(type_mapping, type_engine), + StructDeclaration(ref mut decl_id) => decl_id.copy_types(type_mapping, type_engine), + EnumDeclaration(ref mut decl_id) => decl_id.copy_types(type_mapping, type_engine), + ImplTrait(decl_id) => decl_id.copy_types(type_mapping, type_engine), // generics in an ABI is unsupported by design AbiDeclaration(..) | ConstantDeclaration(_) @@ -48,15 +75,19 @@ impl CopyTypes for TyDeclaration { } impl ReplaceSelfType for TyDeclaration { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { use TyDeclaration::*; match self { - VariableDeclaration(ref mut var_decl) => var_decl.replace_self_type(self_type), - FunctionDeclaration(ref mut decl_id) => decl_id.replace_self_type(self_type), - TraitDeclaration(ref mut decl_id) => decl_id.replace_self_type(self_type), - StructDeclaration(ref mut decl_id) => decl_id.replace_self_type(self_type), - EnumDeclaration(ref mut decl_id) => decl_id.replace_self_type(self_type), - ImplTrait(decl_id) => decl_id.replace_self_type(self_type), + VariableDeclaration(ref mut var_decl) => { + var_decl.replace_self_type(type_engine, self_type) + } + FunctionDeclaration(ref mut decl_id) => { + decl_id.replace_self_type(type_engine, self_type) + } + TraitDeclaration(ref mut decl_id) => decl_id.replace_self_type(type_engine, self_type), + StructDeclaration(ref mut decl_id) => decl_id.replace_self_type(type_engine, self_type), + EnumDeclaration(ref mut decl_id) => decl_id.replace_self_type(type_engine, self_type), + ImplTrait(decl_id) => decl_id.replace_self_type(type_engine, self_type), // generics in an ABI is unsupported by design AbiDeclaration(..) | ConstantDeclaration(_) @@ -86,8 +117,8 @@ impl Spanned for TyDeclaration { } } -impl fmt::Display for TyDeclaration { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl DisplayWithTypeEngine for TyDeclaration { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>, type_engine: &TypeEngine) -> std::fmt::Result { write!( f, "{} declaration ({})", @@ -111,10 +142,12 @@ impl fmt::Display for TyDeclaration { builder.push_str(name.as_str()); builder.push_str(": "); builder.push_str( - &crate::type_system::look_up_type_id(*type_ascription).to_string(), + &type_engine + .help_out(type_engine.look_up_type_id(*type_ascription)) + .to_string(), ); builder.push_str(" = "); - builder.push_str(&body.to_string()); + builder.push_str(&type_engine.help_out(body).to_string()); builder } TyDeclaration::FunctionDeclaration(decl_id) => { @@ -435,7 +468,11 @@ impl TyDeclaration { } } - pub(crate) fn return_type(&self, access_span: &Span) -> CompileResult { + pub(crate) fn return_type( + &self, + access_span: &Span, + type_engine: &TypeEngine, + ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; let type_id = match self { @@ -456,7 +493,7 @@ impl TyDeclaration { warnings, errors ); - decl.create_type_id() + decl.create_type_id(type_engine) } TyDeclaration::EnumDeclaration(decl_id) => { let decl = check!( @@ -465,7 +502,7 @@ impl TyDeclaration { warnings, errors ); - decl.create_type_id() + decl.create_type_id(type_engine) } TyDeclaration::StorageDeclaration(decl_id) => { let storage_decl = check!( @@ -474,7 +511,7 @@ impl TyDeclaration { warnings, errors ); - insert_type(TypeInfo::Storage { + type_engine.insert_type(TypeInfo::Storage { fields: storage_decl.fields_as_typed_struct_fields(), }) } @@ -482,7 +519,7 @@ impl TyDeclaration { decl => { errors.push(CompileError::NotAType { span: decl.span(), - name: decl.to_string(), + name: type_engine.help_out(decl).to_string(), actually_is: decl.friendly_name(), }); return err(warnings, errors); diff --git a/sway-core/src/language/ty/declaration/enum.rs b/sway-core/src/language/ty/declaration/enum.rs index c4c83f5fca9..a8f206fc622 100644 --- a/sway-core/src/language/ty/declaration/enum.rs +++ b/sway-core/src/language/ty/declaration/enum.rs @@ -3,9 +3,10 @@ use std::hash::{Hash, Hasher}; use sway_error::error::CompileError; use sway_types::{Ident, Span, Spanned}; +use crate::PartialEqWithTypeEngine; use crate::{error::*, language::Visibility, transform, type_system::*}; -#[derive(Clone, Debug, Eq)] +#[derive(Clone, Debug)] pub struct TyEnumDeclaration { pub name: Ident, pub type_parameters: Vec, @@ -18,40 +19,41 @@ pub struct TyEnumDeclaration { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyEnumDeclaration { - fn eq(&self, other: &Self) -> bool { +impl EqWithTypeEngine for TyEnumDeclaration {} +impl PartialEqWithTypeEngine for TyEnumDeclaration { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { self.name == other.name - && self.type_parameters == other.type_parameters - && self.variants == other.variants + && self.type_parameters.eq(&other.type_parameters, type_engine) + && self.variants.eq(&other.variants, type_engine) && self.visibility == other.visibility } } impl CopyTypes for TyEnumDeclaration { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { self.variants .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); self.type_parameters .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); } } impl ReplaceSelfType for TyEnumDeclaration { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { self.variants .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); self.type_parameters .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); } } impl CreateTypeId for TyEnumDeclaration { - fn create_type_id(&self) -> TypeId { - insert_type(TypeInfo::Enum { + fn create_type_id(&self, type_engine: &TypeEngine) -> TypeId { + type_engine.insert_type(TypeInfo::Enum { name: self.name.clone(), variant_types: self.variants.clone(), type_parameters: self.type_parameters.clone(), @@ -100,7 +102,7 @@ impl TyEnumDeclaration { } } -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone)] pub struct TyEnumVariant { pub name: Ident, pub type_id: TypeId, @@ -114,10 +116,12 @@ pub struct TyEnumVariant { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl Hash for TyEnumVariant { - fn hash(&self, state: &mut H) { +impl HashWithTypeEngine for TyEnumVariant { + fn hash(&self, state: &mut H, type_engine: &TypeEngine) { self.name.hash(state); - look_up_type_id(self.type_id).hash(state); + type_engine + .look_up_type_id(self.type_id) + .hash(state, type_engine); self.tag.hash(state); } } @@ -125,22 +129,25 @@ impl Hash for TyEnumVariant { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyEnumVariant { - fn eq(&self, other: &Self) -> bool { +impl EqWithTypeEngine for TyEnumVariant {} +impl PartialEqWithTypeEngine for TyEnumVariant { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { self.name == other.name - && look_up_type_id(self.type_id) == look_up_type_id(other.type_id) + && type_engine + .look_up_type_id(self.type_id) + .eq(&type_engine.look_up_type_id(other.type_id), type_engine) && self.tag == other.tag } } impl CopyTypes for TyEnumVariant { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - self.type_id.copy_types(type_mapping); + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + self.type_id.copy_types(type_mapping, type_engine); } } impl ReplaceSelfType for TyEnumVariant { - fn replace_self_type(&mut self, self_type: TypeId) { - self.type_id.replace_self_type(self_type); + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + self.type_id.replace_self_type(type_engine, self_type); } } diff --git a/sway-core/src/language/ty/declaration/function.rs b/sway-core/src/language/ty/declaration/function.rs index 1e832e125f8..370b2671c50 100644 --- a/sway-core/src/language/ty/declaration/function.rs +++ b/sway-core/src/language/ty/declaration/function.rs @@ -11,7 +11,7 @@ use crate::{ use sway_types::constants::{INLINE_ALWAYS_NAME, INLINE_NEVER_NAME}; -#[derive(Clone, Debug, Eq)] +#[derive(Clone, Debug)] pub struct TyFunctionDeclaration { pub name: Ident, pub body: TyCodeBlock, @@ -45,13 +45,16 @@ impl From<&TyFunctionDeclaration> for TyAstNode { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyFunctionDeclaration { - fn eq(&self, other: &Self) -> bool { +impl EqWithTypeEngine for TyFunctionDeclaration {} +impl PartialEqWithTypeEngine for TyFunctionDeclaration { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { self.name == other.name - && self.body == other.body - && self.parameters == other.parameters - && look_up_type_id(self.return_type) == look_up_type_id(other.return_type) - && self.type_parameters == other.type_parameters + && self.body.eq(&other.body, type_engine) + && self.parameters.eq(&other.parameters, type_engine) + && type_engine + .look_up_type_id(self.return_type) + .eq(&type_engine.look_up_type_id(other.return_type), type_engine) + && self.type_parameters.eq(&other.type_parameters, type_engine) && self.visibility == other.visibility && self.is_contract_call == other.is_contract_call && self.purity == other.purity @@ -59,34 +62,34 @@ impl PartialEq for TyFunctionDeclaration { } impl CopyTypes for TyFunctionDeclaration { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { self.type_parameters .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); self.parameters .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); - self.return_type.copy_types(type_mapping); - self.body.copy_types(type_mapping); + .for_each(|x| x.copy_types(type_mapping, type_engine)); + self.return_type.copy_types(type_mapping, type_engine); + self.body.copy_types(type_mapping, type_engine); } } impl ReplaceSelfType for TyFunctionDeclaration { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { self.type_parameters .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); self.parameters .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); - self.return_type.replace_self_type(self_type); - self.body.replace_self_type(self_type); + .for_each(|x| x.replace_self_type(type_engine, self_type)); + self.return_type.replace_self_type(type_engine, self_type); + self.body.replace_self_type(type_engine, self_type); } } impl ReplaceDecls for TyFunctionDeclaration { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping) { - self.body.replace_decls(decl_mapping); + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { + self.body.replace_decls(decl_mapping, type_engine); } } @@ -107,25 +110,32 @@ impl MonomorphizeHelper for TyFunctionDeclaration { } impl UnconstrainedTypeParameters for TyFunctionDeclaration { - fn type_parameter_is_unconstrained(&self, type_parameter: &TypeParameter) -> bool { - let type_parameter_info = look_up_type_id(type_parameter.type_id); + fn type_parameter_is_unconstrained( + &self, + type_engine: &TypeEngine, + type_parameter: &TypeParameter, + ) -> bool { + let type_parameter_info = type_engine.look_up_type_id(type_parameter.type_id); if self .type_parameters .iter() - .map(|type_param| look_up_type_id(type_param.type_id)) - .any(|x| x == type_parameter_info) + .map(|type_param| type_engine.look_up_type_id(type_param.type_id)) + .any(|x| x.eq(&type_parameter_info, type_engine)) { return false; } if self .parameters .iter() - .map(|param| look_up_type_id(param.type_id)) - .any(|x| x == type_parameter_info) + .map(|param| type_engine.look_up_type_id(param.type_id)) + .any(|x| x.eq(&type_parameter_info, type_engine)) { return true; } - if look_up_type_id(self.return_type) == type_parameter_info { + if type_engine + .look_up_type_id(self.return_type) + .eq(&type_parameter_info, type_engine) + { return true; } @@ -136,7 +146,10 @@ impl UnconstrainedTypeParameters for TyFunctionDeclaration { impl TyFunctionDeclaration { /// Used to create a stubbed out function when the function fails to /// compile, preventing cascading namespace errors. - pub(crate) fn error(decl: parsed::FunctionDeclaration) -> TyFunctionDeclaration { + pub(crate) fn error( + decl: parsed::FunctionDeclaration, + type_engine: &TypeEngine, + ) -> TyFunctionDeclaration { let parsed::FunctionDeclaration { name, return_type, @@ -146,7 +159,7 @@ impl TyFunctionDeclaration { purity, .. } = decl; - let initial_return_type = insert_type(return_type); + let initial_return_type = type_engine.insert_type(return_type); TyFunctionDeclaration { purity, name, @@ -177,12 +190,15 @@ impl TyFunctionDeclaration { } } - pub fn to_fn_selector_value_untruncated(&self) -> CompileResult> { + pub fn to_fn_selector_value_untruncated( + &self, + type_engine: &TypeEngine, + ) -> CompileResult> { let mut errors = vec![]; let mut warnings = vec![]; let mut hasher = Sha256::new(); let data = check!( - self.to_selector_name(), + self.to_selector_name(type_engine), return err(warnings, errors), warnings, errors @@ -195,11 +211,11 @@ impl TyFunctionDeclaration { /// Converts a [TyFunctionDeclaration] into a value that is to be used in contract function /// selectors. /// Hashes the name and parameters using SHA256, and then truncates to four bytes. - pub fn to_fn_selector_value(&self) -> CompileResult<[u8; 4]> { + pub fn to_fn_selector_value(&self, type_engine: &TypeEngine) -> CompileResult<[u8; 4]> { let mut errors = vec![]; let mut warnings = vec![]; let hash = check!( - self.to_fn_selector_value_untruncated(), + self.to_fn_selector_value_untruncated(type_engine), return err(warnings, errors), warnings, errors @@ -210,7 +226,7 @@ impl TyFunctionDeclaration { ok(buf, warnings, errors) } - pub fn to_selector_name(&self) -> CompileResult { + pub fn to_selector_name(&self, type_engine: &TypeEngine) -> CompileResult { let mut errors = vec![]; let mut warnings = vec![]; let named_params = self @@ -220,9 +236,10 @@ impl TyFunctionDeclaration { |TyFunctionParameter { type_id, type_span, .. }| { - to_typeinfo(*type_id, type_span) + type_engine + .to_typeinfo(*type_id, type_span) .expect("unreachable I think?") - .to_selector_name(type_span) + .to_selector_name(type_engine, type_span) }, ) .filter_map(|name| name.ok(&mut warnings, &mut errors)) @@ -237,6 +254,7 @@ impl TyFunctionDeclaration { pub(crate) fn generate_json_abi_function( &self, + type_engine: &TypeEngine, types: &mut Vec, ) -> JsonABIFunction { // A list of all `JsonTypeDeclaration`s needed for inputs @@ -244,23 +262,35 @@ impl TyFunctionDeclaration { .parameters .iter() .map(|x| JsonTypeDeclaration { - type_id: *x.initial_type_id, - type_field: x.initial_type_id.get_json_type_str(x.type_id), - components: x.initial_type_id.get_json_type_components(types, x.type_id), - type_parameters: x.type_id.get_json_type_parameters(types, x.type_id), + type_id: x.initial_type_id.index(), + type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), + components: x.initial_type_id.get_json_type_components( + type_engine, + types, + x.type_id, + ), + type_parameters: x + .type_id + .get_json_type_parameters(type_engine, types, x.type_id), }) .collect::>(); // The single `JsonTypeDeclaration` needed for the output let output_type = JsonTypeDeclaration { - type_id: *self.initial_return_type, - type_field: self.initial_return_type.get_json_type_str(self.return_type), - components: self - .return_type - .get_json_type_components(types, self.return_type), - type_parameters: self - .return_type - .get_json_type_parameters(types, self.return_type), + type_id: self.initial_return_type.index(), + type_field: self + .initial_return_type + .get_json_type_str(type_engine, self.return_type), + components: self.return_type.get_json_type_components( + type_engine, + types, + self.return_type, + ), + type_parameters: self.return_type.get_json_type_parameters( + type_engine, + types, + self.return_type, + ), }; // Add the new types to `types` @@ -275,16 +305,22 @@ impl TyFunctionDeclaration { .iter() .map(|x| JsonTypeApplication { name: x.name.to_string(), - type_id: *x.initial_type_id, - type_arguments: x.initial_type_id.get_json_type_arguments(types, x.type_id), + type_id: x.initial_type_id.index(), + type_arguments: x.initial_type_id.get_json_type_arguments( + type_engine, + types, + x.type_id, + ), }) .collect(), output: JsonTypeApplication { name: "".to_string(), - type_id: *self.initial_return_type, - type_arguments: self - .initial_return_type - .get_json_type_arguments(types, self.return_type), + type_id: self.initial_return_type.index(), + type_arguments: self.initial_return_type.get_json_type_arguments( + type_engine, + types, + self.return_type, + ), }, } } @@ -323,7 +359,7 @@ impl TyFunctionDeclaration { } } -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone)] pub struct TyFunctionParameter { pub name: Ident, pub is_reference: bool, @@ -337,23 +373,26 @@ pub struct TyFunctionParameter { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyFunctionParameter { - fn eq(&self, other: &Self) -> bool { +impl EqWithTypeEngine for TyFunctionParameter {} +impl PartialEqWithTypeEngine for TyFunctionParameter { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { self.name == other.name - && look_up_type_id(self.type_id) == look_up_type_id(other.type_id) + && type_engine + .look_up_type_id(self.type_id) + .eq(&type_engine.look_up_type_id(other.type_id), type_engine) && self.is_mutable == other.is_mutable } } impl CopyTypes for TyFunctionParameter { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - self.type_id.copy_types(type_mapping); + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + self.type_id.copy_types(type_mapping, type_engine); } } impl ReplaceSelfType for TyFunctionParameter { - fn replace_self_type(&mut self, self_type: TypeId) { - self.type_id.replace_self_type(self_type); + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + self.type_id.replace_self_type(type_engine, self_type); } } diff --git a/sway-core/src/language/ty/declaration/impl_trait.rs b/sway-core/src/language/ty/declaration/impl_trait.rs index a89e02487da..1edde62e789 100644 --- a/sway-core/src/language/ty/declaration/impl_trait.rs +++ b/sway-core/src/language/ty/declaration/impl_trait.rs @@ -2,7 +2,7 @@ use sway_types::Span; use crate::{declaration_engine::DeclarationId, language::CallPath, type_system::*}; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct TyImplTrait { pub impl_type_parameters: Vec, pub trait_name: CallPath, @@ -13,26 +13,44 @@ pub struct TyImplTrait { pub span: Span, } +impl EqWithTypeEngine for TyImplTrait {} +impl PartialEqWithTypeEngine for TyImplTrait { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.impl_type_parameters + .eq(&rhs.impl_type_parameters, type_engine) + && self.trait_name == rhs.trait_name + && self + .trait_type_arguments + .eq(&rhs.trait_type_arguments, type_engine) + && self.methods.eq(&rhs.methods, type_engine) + && self.implementing_for_type_id == rhs.implementing_for_type_id + && self.type_implementing_for_span == rhs.type_implementing_for_span + && self.span == rhs.span + } +} + impl CopyTypes for TyImplTrait { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { self.impl_type_parameters .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); - self.implementing_for_type_id.copy_types(type_mapping); + .for_each(|x| x.copy_types(type_mapping, type_engine)); + self.implementing_for_type_id + .copy_types(type_mapping, type_engine); self.methods .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); } } impl ReplaceSelfType for TyImplTrait { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { self.impl_type_parameters .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); - self.implementing_for_type_id.replace_self_type(self_type); + .for_each(|x| x.replace_self_type(type_engine, self_type)); + self.implementing_for_type_id + .replace_self_type(type_engine, self_type); self.methods .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); } } diff --git a/sway-core/src/language/ty/declaration/storage.rs b/sway-core/src/language/ty/declaration/storage.rs index 3dfa8b0e5ab..cbf72ac23d0 100644 --- a/sway-core/src/language/ty/declaration/storage.rs +++ b/sway-core/src/language/ty/declaration/storage.rs @@ -1,19 +1,22 @@ -use derivative::Derivative; use sway_error::error::CompileError; use sway_types::{state::StateIndex, Ident, Span, Spanned}; use crate::{error::*, language::ty::*, transform, type_system::*}; -#[derive(Clone, Debug, Derivative)] -#[derivative(PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct TyStorageDeclaration { pub fields: Vec, - #[derivative(PartialEq = "ignore")] - #[derivative(Eq(bound = ""))] pub span: Span, pub attributes: transform::AttributesMap, } +impl EqWithTypeEngine for TyStorageDeclaration {} +impl PartialEqWithTypeEngine for TyStorageDeclaration { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.fields.eq(&rhs.fields, type_engine) && self.attributes == rhs.attributes + } +} + impl Spanned for TyStorageDeclaration { fn span(&self) -> Span { self.span.clone() @@ -37,6 +40,7 @@ impl TyStorageDeclaration { /// been declared as a part of storage, return an error. pub fn apply_storage_load( &self, + type_engine: &TypeEngine, fields: Vec, storage_fields: &[TyStorageField], ) -> CompileResult<(TyStorageAccess, TypeId)> { @@ -72,12 +76,10 @@ impl TyStorageDeclaration { span: first_field.span(), }); - fn update_available_struct_fields(id: TypeId) -> Vec { - match crate::type_system::look_up_type_id(id) { - TypeInfo::Struct { fields, .. } => fields, - _ => vec![], - } - } + let update_available_struct_fields = |id: TypeId| match type_engine.look_up_type_id(id) { + TypeInfo::Struct { fields, .. } => fields, + _ => vec![], + }; // if the previously iterated type was a struct, put its fields here so we know that, // in the case of a subfield, we can type check the that the subfield exists and its type. @@ -152,7 +154,7 @@ impl TyStorageDeclaration { } } -#[derive(Clone, Debug, Eq)] +#[derive(Clone, Debug)] pub struct TyStorageField { pub name: Ident, pub type_id: TypeId, @@ -165,10 +167,13 @@ pub struct TyStorageField { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyStorageField { - fn eq(&self, other: &Self) -> bool { +impl EqWithTypeEngine for TyStorageField {} +impl PartialEqWithTypeEngine for TyStorageField { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { self.name == other.name - && look_up_type_id(self.type_id) == look_up_type_id(other.type_id) - && self.initializer == other.initializer + && type_engine + .look_up_type_id(self.type_id) + .eq(&type_engine.look_up_type_id(other.type_id), type_engine) + && self.initializer.eq(&other.initializer, type_engine) } } diff --git a/sway-core/src/language/ty/declaration/struct.rs b/sway-core/src/language/ty/declaration/struct.rs index b05982a87ef..efa99be5de4 100644 --- a/sway-core/src/language/ty/declaration/struct.rs +++ b/sway-core/src/language/ty/declaration/struct.rs @@ -5,7 +5,7 @@ use sway_types::{Ident, Span, Spanned}; use crate::{error::*, language::Visibility, transform, type_system::*}; -#[derive(Clone, Debug, Eq)] +#[derive(Clone, Debug)] pub struct TyStructDeclaration { pub name: Ident, pub fields: Vec, @@ -18,40 +18,41 @@ pub struct TyStructDeclaration { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyStructDeclaration { - fn eq(&self, other: &Self) -> bool { +impl EqWithTypeEngine for TyStructDeclaration {} +impl PartialEqWithTypeEngine for TyStructDeclaration { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { self.name == other.name - && self.fields == other.fields - && self.type_parameters == other.type_parameters + && self.fields.eq(&other.fields, type_engine) + && self.type_parameters.eq(&other.type_parameters, type_engine) && self.visibility == other.visibility } } impl CopyTypes for TyStructDeclaration { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { self.fields .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); self.type_parameters .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); } } impl ReplaceSelfType for TyStructDeclaration { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { self.fields .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); self.type_parameters .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); } } impl CreateTypeId for TyStructDeclaration { - fn create_type_id(&self) -> TypeId { - insert_type(TypeInfo::Struct { + fn create_type_id(&self, type_engine: &TypeEngine) -> TypeId { + type_engine.insert_type(TypeInfo::Struct { name: self.name.clone(), fields: self.fields.clone(), type_parameters: self.type_parameters.clone(), @@ -102,7 +103,7 @@ impl TyStructDeclaration { } } -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone)] pub struct TyStructField { pub name: Ident, pub type_id: TypeId, @@ -115,30 +116,36 @@ pub struct TyStructField { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl Hash for TyStructField { - fn hash(&self, state: &mut H) { +impl HashWithTypeEngine for TyStructField { + fn hash(&self, state: &mut H, type_engine: &TypeEngine) { self.name.hash(state); - look_up_type_id(self.type_id).hash(state); + type_engine + .look_up_type_id(self.type_id) + .hash(state, type_engine); } } // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyStructField { - fn eq(&self, other: &Self) -> bool { - self.name == other.name && look_up_type_id(self.type_id) == look_up_type_id(other.type_id) +impl EqWithTypeEngine for TyStructField {} +impl PartialEqWithTypeEngine for TyStructField { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { + self.name == other.name + && type_engine + .look_up_type_id(self.type_id) + .eq(&type_engine.look_up_type_id(other.type_id), type_engine) } } impl CopyTypes for TyStructField { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - self.type_id.copy_types(type_mapping); + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + self.type_id.copy_types(type_mapping, type_engine); } } impl ReplaceSelfType for TyStructField { - fn replace_self_type(&mut self, self_type: TypeId) { - self.type_id.replace_self_type(self_type); + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + self.type_id.replace_self_type(type_engine, self_type); } } diff --git a/sway-core/src/language/ty/declaration/trait.rs b/sway-core/src/language/ty/declaration/trait.rs index 3d421a9f07f..f81714f4f77 100644 --- a/sway-core/src/language/ty/declaration/trait.rs +++ b/sway-core/src/language/ty/declaration/trait.rs @@ -1,4 +1,3 @@ -use derivative::Derivative; use sway_types::{Ident, Span}; use crate::{ @@ -8,8 +7,7 @@ use crate::{ type_system::*, }; -#[derive(Clone, Debug, Derivative)] -#[derivative(PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct TyTraitDeclaration { pub name: Ident, pub type_parameters: Vec, @@ -21,17 +19,33 @@ pub struct TyTraitDeclaration { pub span: Span, } +impl EqWithTypeEngine for TyTraitDeclaration {} +impl PartialEqWithTypeEngine for TyTraitDeclaration { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.name == rhs.name + && self.type_parameters.eq(&rhs.type_parameters, type_engine) + && self + .interface_surface + .eq(&rhs.interface_surface, type_engine) + && self.methods.eq(&rhs.methods, type_engine) + && self.supertraits == rhs.supertraits + && self.visibility == rhs.visibility + && self.attributes == rhs.attributes + && self.span == rhs.span + } +} + impl CopyTypes for TyTraitDeclaration { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { self.type_parameters .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); self.interface_surface .iter_mut() .for_each(|function_decl_id| { let new_decl_id = function_decl_id .clone() - .copy_types_and_insert_new(type_mapping); + .copy_types_and_insert_new(type_mapping, type_engine); function_decl_id.replace_id(*new_decl_id); }); // we don't have to type check the methods because it hasn't been type checked yet @@ -39,16 +53,16 @@ impl CopyTypes for TyTraitDeclaration { } impl ReplaceSelfType for TyTraitDeclaration { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { self.type_parameters .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); self.interface_surface .iter_mut() .for_each(|function_decl_id| { let new_decl_id = function_decl_id .clone() - .replace_self_type_and_insert_new(self_type); + .replace_self_type_and_insert_new(type_engine, self_type); function_decl_id.replace_id(*new_decl_id); }); // we don't have to type check the methods because it hasn't been type checked yet diff --git a/sway-core/src/language/ty/declaration/trait_fn.rs b/sway-core/src/language/ty/declaration/trait_fn.rs index df45da01394..81ab6cc5ed3 100644 --- a/sway-core/src/language/ty/declaration/trait_fn.rs +++ b/sway-core/src/language/ty/declaration/trait_fn.rs @@ -1,4 +1,3 @@ -use derivative::Derivative; use sway_types::{Ident, Span}; use crate::{ @@ -7,34 +6,42 @@ use crate::{ type_system::*, }; -#[derive(Clone, Debug, Derivative)] -#[derivative(PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct TyTraitFn { pub name: Ident, pub(crate) purity: Purity, pub parameters: Vec, pub return_type: TypeId, - #[derivative(PartialEq = "ignore")] - #[derivative(Eq(bound = ""))] pub return_type_span: Span, pub attributes: transform::AttributesMap, } +impl EqWithTypeEngine for TyTraitFn {} +impl PartialEqWithTypeEngine for TyTraitFn { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.name == rhs.name + && self.purity == rhs.purity + && self.parameters.eq(&rhs.parameters, type_engine) + && self.return_type == rhs.return_type + && self.attributes == rhs.attributes + } +} + impl CopyTypes for TyTraitFn { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { self.parameters .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); - self.return_type.copy_types(type_mapping); + .for_each(|x| x.copy_types(type_mapping, type_engine)); + self.return_type.copy_types(type_mapping, type_engine); } } impl ReplaceSelfType for TyTraitFn { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { self.parameters .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); - self.return_type.replace_self_type(self_type); + .for_each(|x| x.replace_self_type(type_engine, self_type)); + self.return_type.replace_self_type(type_engine, self_type); } } diff --git a/sway-core/src/language/ty/declaration/variable.rs b/sway-core/src/language/ty/declaration/variable.rs index 19a458ab2b8..fa2d93343dd 100644 --- a/sway-core/src/language/ty/declaration/variable.rs +++ b/sway-core/src/language/ty/declaration/variable.rs @@ -2,7 +2,7 @@ use sway_types::{Ident, Span}; use crate::{language::ty::*, type_system::*}; -#[derive(Clone, Debug, Eq)] +#[derive(Clone, Debug)] pub struct TyVariableDeclaration { pub name: Ident, pub body: TyExpression, @@ -14,25 +14,30 @@ pub struct TyVariableDeclaration { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyVariableDeclaration { - fn eq(&self, other: &Self) -> bool { +impl EqWithTypeEngine for TyVariableDeclaration {} +impl PartialEqWithTypeEngine for TyVariableDeclaration { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { self.name == other.name - && self.body == other.body + && self.body.eq(&other.body, type_engine) && self.mutability == other.mutability - && look_up_type_id(self.type_ascription) == look_up_type_id(other.type_ascription) + && type_engine.look_up_type_id(self.type_ascription).eq( + &type_engine.look_up_type_id(other.type_ascription), + type_engine, + ) } } impl CopyTypes for TyVariableDeclaration { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - self.type_ascription.copy_types(type_mapping); - self.body.copy_types(type_mapping) + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + self.type_ascription.copy_types(type_mapping, type_engine); + self.body.copy_types(type_mapping, type_engine) } } impl ReplaceSelfType for TyVariableDeclaration { - fn replace_self_type(&mut self, self_type: TypeId) { - self.type_ascription.replace_self_type(self_type); - self.body.replace_self_type(self_type) + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + self.type_ascription + .replace_self_type(type_engine, self_type); + self.body.replace_self_type(type_engine, self_type) } } diff --git a/sway-core/src/language/ty/expression/asm.rs b/sway-core/src/language/ty/expression/asm.rs index d6b91d82300..760646297a1 100644 --- a/sway-core/src/language/ty/expression/asm.rs +++ b/sway-core/src/language/ty/expression/asm.rs @@ -11,11 +11,11 @@ pub struct TyAsmRegisterDeclaration { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyAsmRegisterDeclaration { - fn eq(&self, other: &Self) -> bool { +impl PartialEqWithTypeEngine for TyAsmRegisterDeclaration { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { self.name == other.name - && if let (Some(l), Some(r)) = (self.initializer.clone(), other.initializer.clone()) { - l == r + && if let (Some(l), Some(r)) = (&self.initializer, &other.initializer) { + l.eq(r, type_engine) } else { true } @@ -23,17 +23,17 @@ impl PartialEq for TyAsmRegisterDeclaration { } impl CopyTypes for TyAsmRegisterDeclaration { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { if let Some(ref mut initializer) = self.initializer { - initializer.copy_types(type_mapping) + initializer.copy_types(type_mapping, type_engine) } } } impl ReplaceSelfType for TyAsmRegisterDeclaration { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { if let Some(ref mut initializer) = self.initializer { - initializer.replace_self_type(self_type) + initializer.replace_self_type(type_engine, self_type) } } } diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index 4936e38f0ed..ebdb51bdb7c 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -10,7 +10,7 @@ use crate::{ types::DeterministicallyAborts, }; -#[derive(Clone, Debug, Eq)] +#[derive(Clone, Debug)] pub struct TyExpression { pub expression: TyExpressionVariant, pub return_type: TypeId, @@ -20,40 +20,43 @@ pub struct TyExpression { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyExpression { - fn eq(&self, other: &Self) -> bool { - self.expression == other.expression - && look_up_type_id(self.return_type) == look_up_type_id(other.return_type) +impl EqWithTypeEngine for TyExpression {} +impl PartialEqWithTypeEngine for TyExpression { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { + self.expression.eq(&other.expression, type_engine) + && type_engine + .look_up_type_id(self.return_type) + .eq(&type_engine.look_up_type_id(other.return_type), type_engine) } } impl CopyTypes for TyExpression { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - self.return_type.copy_types(type_mapping); - self.expression.copy_types(type_mapping); + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + self.return_type.copy_types(type_mapping, type_engine); + self.expression.copy_types(type_mapping, type_engine); } } impl ReplaceSelfType for TyExpression { - fn replace_self_type(&mut self, self_type: TypeId) { - self.return_type.replace_self_type(self_type); - self.expression.replace_self_type(self_type); + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + self.return_type.replace_self_type(type_engine, self_type); + self.expression.replace_self_type(type_engine, self_type); } } impl ReplaceDecls for TyExpression { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping) { - self.expression.replace_decls(decl_mapping); + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { + self.expression.replace_decls(decl_mapping, type_engine); } } -impl fmt::Display for TyExpression { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl DisplayWithTypeEngine for TyExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { write!( f, "{} ({})", - self.expression, - look_up_type_id(self.return_type) + type_engine.help_out(&self.expression), + type_engine.help_out(self.return_type) ) } } @@ -132,7 +135,7 @@ impl CollectTypesMetadata for TyExpression { StructExpression { fields, span, .. } => { if let TypeInfo::Struct { type_parameters, .. - } = look_up_type_id(self.return_type) + } = ctx.type_engine.look_up_type_id(self.return_type) { for type_parameter in type_parameters { ctx.call_site_insert(type_parameter.type_id, span.clone()); @@ -473,10 +476,10 @@ impl DeterministicallyAborts for TyExpression { } impl TyExpression { - pub(crate) fn error(span: Span) -> TyExpression { + pub(crate) fn error(span: Span, type_engine: &TypeEngine) -> TyExpression { TyExpression { expression: TyExpressionVariant::Tuple { fields: vec![] }, - return_type: insert_type(TypeInfo::ErrorRecovery), + return_type: type_engine.insert_type(TypeInfo::ErrorRecovery), span, } } diff --git a/sway-core/src/language/ty/expression/expression_variant.rs b/sway-core/src/language/ty/expression/expression_variant.rs index 86fdc9101a8..a4d4c43bf16 100644 --- a/sway-core/src/language/ty/expression/expression_variant.rs +++ b/sway-core/src/language/ty/expression/expression_variant.rs @@ -3,7 +3,6 @@ use std::{ fmt::{self, Write}, }; -use derivative::Derivative; use sway_types::{state::StateIndex, Ident, Span}; use crate::{ @@ -12,24 +11,20 @@ use crate::{ type_system::*, }; -#[derive(Clone, Debug, Derivative)] -#[derivative(Eq)] +#[derive(Clone, Debug)] pub enum TyExpressionVariant { Literal(Literal), FunctionApplication { call_path: CallPath, - #[derivative(Eq(bound = ""))] contract_call_params: HashMap, arguments: Vec<(Ident, TyExpression)>, function_decl_id: DeclarationId, /// If this is `Some(val)` then `val` is the metadata. If this is `None`, then /// there is no selector. self_state_idx: Option, - #[derivative(Eq(bound = ""))] selector: Option, }, LazyOperator { - #[derivative(Eq(bound = ""))] op: LazyOp, lhs: Box, rhs: Box, @@ -129,8 +124,9 @@ pub enum TyExpressionVariant { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyExpressionVariant { - fn eq(&self, other: &Self) -> bool { +impl EqWithTypeEngine for TyExpressionVariant {} +impl PartialEqWithTypeEngine for TyExpressionVariant { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { match (self, other) { (Self::Literal(l0), Self::Literal(r0)) => l0 == r0, ( @@ -152,8 +148,12 @@ impl PartialEq for TyExpressionVariant { let r_function_decl = de_get_function(r_function_decl_id.clone(), &Span::dummy()).unwrap(); l_name == r_name - && l_arguments == r_arguments - && l_function_decl.body == r_function_decl.body + && l_arguments.len() == r_arguments.len() + && l_arguments + .iter() + .zip(r_arguments.iter()) + .all(|((xa, xb), (ya, yb))| xa == ya && xb.eq(yb, type_engine)) + && l_function_decl.body.eq(&r_function_decl.body, type_engine) } ( Self::LazyOperator { @@ -166,7 +166,11 @@ impl PartialEq for TyExpressionVariant { lhs: r_lhs, rhs: r_rhs, }, - ) => l_op == r_op && (**l_lhs) == (**r_lhs) && (**l_rhs) == (**r_rhs), + ) => { + l_op == r_op + && (**l_lhs).eq(&(**r_lhs), type_engine) + && (**l_rhs).eq(&(**r_rhs), type_engine) + } ( Self::VariableExpression { name: l_name, @@ -180,7 +184,7 @@ impl PartialEq for TyExpressionVariant { }, ) => l_name == r_name && l_span == r_span && l_mutability == r_mutability, (Self::Tuple { fields: l_fields }, Self::Tuple { fields: r_fields }) => { - l_fields == r_fields + l_fields.eq(r_fields, type_engine) } ( Self::Array { @@ -189,7 +193,7 @@ impl PartialEq for TyExpressionVariant { Self::Array { contents: r_contents, }, - ) => l_contents == r_contents, + ) => l_contents.eq(r_contents, type_engine), ( Self::ArrayIndex { prefix: l_prefix, @@ -199,7 +203,9 @@ impl PartialEq for TyExpressionVariant { prefix: r_prefix, index: r_index, }, - ) => (**l_prefix) == (**r_prefix) && (**l_index) == (**r_index), + ) => { + (**l_prefix).eq(&**r_prefix, type_engine) && (**l_index).eq(&**r_index, type_engine) + } ( Self::StructExpression { struct_name: l_struct_name, @@ -213,10 +219,10 @@ impl PartialEq for TyExpressionVariant { }, ) => { l_struct_name == r_struct_name - && l_fields.clone() == r_fields.clone() + && l_fields.eq(r_fields, type_engine) && l_span == r_span } - (Self::CodeBlock(l0), Self::CodeBlock(r0)) => l0 == r0, + (Self::CodeBlock(l0), Self::CodeBlock(r0)) => l0.eq(r0, type_engine), ( Self::IfExp { condition: l_condition, @@ -229,10 +235,10 @@ impl PartialEq for TyExpressionVariant { r#else: r_r, }, ) => { - (**l_condition) == (**r_condition) - && (**l_then) == (**r_then) + (**l_condition).eq(&**r_condition, type_engine) + && (**l_then).eq(&**r_then, type_engine) && if let (Some(l), Some(r)) = (l_r, r_r) { - (**l) == (**r) + (**l).eq(&**r, type_engine) } else { true } @@ -251,7 +257,7 @@ impl PartialEq for TyExpressionVariant { .. }, ) => { - l_registers.clone() == r_registers.clone() + l_registers.eq(r_registers, type_engine) && l_body.clone() == r_body.clone() && l_returns == r_returns } @@ -269,10 +275,12 @@ impl PartialEq for TyExpressionVariant { .. }, ) => { - (**l_prefix) == (**r_prefix) - && l_field_to_access == r_field_to_access - && look_up_type_id(*l_resolved_type_of_parent) - == look_up_type_id(*r_resolved_type_of_parent) + (**l_prefix).eq(&**r_prefix, type_engine) + && l_field_to_access.eq(r_field_to_access, type_engine) + && type_engine.look_up_type_id(*l_resolved_type_of_parent).eq( + &type_engine.look_up_type_id(*r_resolved_type_of_parent), + type_engine, + ) } ( Self::TupleElemAccess { @@ -288,10 +296,12 @@ impl PartialEq for TyExpressionVariant { .. }, ) => { - (**l_prefix) == (**r_prefix) + (**l_prefix).eq(&**r_prefix, type_engine) && l_elem_to_access_num == r_elem_to_access_num - && look_up_type_id(*l_resolved_type_of_parent) - == look_up_type_id(*r_resolved_type_of_parent) + && type_engine.look_up_type_id(*l_resolved_type_of_parent).eq( + &type_engine.look_up_type_id(*r_resolved_type_of_parent), + type_engine, + ) } ( Self::EnumInstantiation { @@ -309,11 +319,11 @@ impl PartialEq for TyExpressionVariant { .. }, ) => { - l_enum_decl == r_enum_decl + l_enum_decl.eq(r_enum_decl, type_engine) && l_variant_name == r_variant_name && l_tag == r_tag && if let (Some(l_contents), Some(r_contents)) = (l_contents, r_contents) { - (**l_contents) == (**r_contents) + (**l_contents).eq(&**r_contents, type_engine) } else { true } @@ -329,8 +339,10 @@ impl PartialEq for TyExpressionVariant { address: r_address, .. }, - ) => l_abi_name == r_abi_name && (**l_address) == (**r_address), - (Self::IntrinsicFunction(l_kind), Self::IntrinsicFunction(r_kind)) => l_kind == r_kind, + ) => l_abi_name == r_abi_name && (**l_address).eq(&**r_address, type_engine), + (Self::IntrinsicFunction(l_kind), Self::IntrinsicFunction(r_kind)) => { + l_kind.eq(r_kind, type_engine) + } ( Self::UnsafeDowncast { exp: l_exp, @@ -340,8 +352,10 @@ impl PartialEq for TyExpressionVariant { exp: r_exp, variant: r_variant, }, - ) => *l_exp == *r_exp && l_variant == r_variant, - (Self::EnumTag { exp: l_exp }, Self::EnumTag { exp: r_exp }) => *l_exp == *r_exp, + ) => l_exp.eq(r_exp, type_engine) && l_variant.eq(r_variant, type_engine), + (Self::EnumTag { exp: l_exp }, Self::EnumTag { exp: r_exp }) => { + l_exp.eq(&**r_exp, type_engine) + } (Self::StorageAccess(l_exp), Self::StorageAccess(r_exp)) => *l_exp == *r_exp, ( Self::WhileLoop { @@ -352,14 +366,14 @@ impl PartialEq for TyExpressionVariant { body: r_body, condition: r_condition, }, - ) => *l_body == *r_body && l_condition == r_condition, + ) => l_body.eq(r_body, type_engine) && l_condition.eq(r_condition, type_engine), _ => false, } } } impl CopyTypes for TyExpressionVariant { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { use TyExpressionVariant::*; match self { Literal(..) => (), @@ -370,28 +384,32 @@ impl CopyTypes for TyExpressionVariant { } => { arguments .iter_mut() - .for_each(|(_ident, expr)| expr.copy_types(type_mapping)); + .for_each(|(_ident, expr)| expr.copy_types(type_mapping, type_engine)); let new_decl_id = function_decl_id .clone() - .copy_types_and_insert_new(type_mapping); + .copy_types_and_insert_new(type_mapping, type_engine); function_decl_id.replace_id(*new_decl_id); } LazyOperator { lhs, rhs, .. } => { - (*lhs).copy_types(type_mapping); - (*rhs).copy_types(type_mapping); + (*lhs).copy_types(type_mapping, type_engine); + (*rhs).copy_types(type_mapping, type_engine); } VariableExpression { .. } => (), - Tuple { fields } => fields.iter_mut().for_each(|x| x.copy_types(type_mapping)), - Array { contents } => contents.iter_mut().for_each(|x| x.copy_types(type_mapping)), + Tuple { fields } => fields + .iter_mut() + .for_each(|x| x.copy_types(type_mapping, type_engine)), + Array { contents } => contents + .iter_mut() + .for_each(|x| x.copy_types(type_mapping, type_engine)), ArrayIndex { prefix, index } => { - (*prefix).copy_types(type_mapping); - (*index).copy_types(type_mapping); - } - StructExpression { fields, .. } => { - fields.iter_mut().for_each(|x| x.copy_types(type_mapping)) + (*prefix).copy_types(type_mapping, type_engine); + (*index).copy_types(type_mapping, type_engine); } + StructExpression { fields, .. } => fields + .iter_mut() + .for_each(|x| x.copy_types(type_mapping, type_engine)), CodeBlock(block) => { - block.copy_types(type_mapping); + block.copy_types(type_mapping, type_engine); } FunctionParameter => (), IfExp { @@ -399,10 +417,10 @@ impl CopyTypes for TyExpressionVariant { then, r#else, } => { - condition.copy_types(type_mapping); - then.copy_types(type_mapping); + condition.copy_types(type_mapping, type_engine); + then.copy_types(type_mapping, type_engine); if let Some(ref mut r#else) = r#else { - r#else.copy_types(type_mapping); + r#else.copy_types(type_mapping, type_engine); } } AsmExpression { @@ -411,7 +429,7 @@ impl CopyTypes for TyExpressionVariant { } => { registers .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); } // like a variable expression but it has multiple parts, // like looking up a field in a struct @@ -421,60 +439,60 @@ impl CopyTypes for TyExpressionVariant { ref mut resolved_type_of_parent, .. } => { - resolved_type_of_parent.copy_types(type_mapping); - field_to_access.copy_types(type_mapping); - prefix.copy_types(type_mapping); + resolved_type_of_parent.copy_types(type_mapping, type_engine); + field_to_access.copy_types(type_mapping, type_engine); + prefix.copy_types(type_mapping, type_engine); } TupleElemAccess { prefix, ref mut resolved_type_of_parent, .. } => { - resolved_type_of_parent.copy_types(type_mapping); - prefix.copy_types(type_mapping); + resolved_type_of_parent.copy_types(type_mapping, type_engine); + prefix.copy_types(type_mapping, type_engine); } EnumInstantiation { enum_decl, contents, .. } => { - enum_decl.copy_types(type_mapping); + enum_decl.copy_types(type_mapping, type_engine); if let Some(ref mut contents) = contents { - contents.copy_types(type_mapping) + contents.copy_types(type_mapping, type_engine) }; } - AbiCast { address, .. } => address.copy_types(type_mapping), + AbiCast { address, .. } => address.copy_types(type_mapping, type_engine), // storage is never generic and cannot be monomorphized StorageAccess { .. } => (), IntrinsicFunction(kind) => { - kind.copy_types(type_mapping); + kind.copy_types(type_mapping, type_engine); } EnumTag { exp } => { - exp.copy_types(type_mapping); + exp.copy_types(type_mapping, type_engine); } UnsafeDowncast { exp, variant } => { - exp.copy_types(type_mapping); - variant.copy_types(type_mapping); + exp.copy_types(type_mapping, type_engine); + variant.copy_types(type_mapping, type_engine); } AbiName(_) => (), WhileLoop { ref mut condition, ref mut body, } => { - condition.copy_types(type_mapping); - body.copy_types(type_mapping); + condition.copy_types(type_mapping, type_engine); + body.copy_types(type_mapping, type_engine); } Break => (), Continue => (), - Reassignment(reassignment) => reassignment.copy_types(type_mapping), + Reassignment(reassignment) => reassignment.copy_types(type_mapping, type_engine), StorageReassignment(..) => (), - Return(stmt) => stmt.copy_types(type_mapping), + Return(stmt) => stmt.copy_types(type_mapping, type_engine), } } } impl ReplaceSelfType for TyExpressionVariant { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { use TyExpressionVariant::*; match self { Literal(..) => (), @@ -485,32 +503,32 @@ impl ReplaceSelfType for TyExpressionVariant { } => { arguments .iter_mut() - .for_each(|(_ident, expr)| expr.replace_self_type(self_type)); + .for_each(|(_ident, expr)| expr.replace_self_type(type_engine, self_type)); let new_decl_id = function_decl_id .clone() - .replace_self_type_and_insert_new(self_type); + .replace_self_type_and_insert_new(type_engine, self_type); function_decl_id.replace_id(*new_decl_id); } LazyOperator { lhs, rhs, .. } => { - (*lhs).replace_self_type(self_type); - (*rhs).replace_self_type(self_type); + (*lhs).replace_self_type(type_engine, self_type); + (*rhs).replace_self_type(type_engine, self_type); } VariableExpression { .. } => (), Tuple { fields } => fields .iter_mut() - .for_each(|x| x.replace_self_type(self_type)), + .for_each(|x| x.replace_self_type(type_engine, self_type)), Array { contents } => contents .iter_mut() - .for_each(|x| x.replace_self_type(self_type)), + .for_each(|x| x.replace_self_type(type_engine, self_type)), ArrayIndex { prefix, index } => { - (*prefix).replace_self_type(self_type); - (*index).replace_self_type(self_type); + (*prefix).replace_self_type(type_engine, self_type); + (*index).replace_self_type(type_engine, self_type); } StructExpression { fields, .. } => fields .iter_mut() - .for_each(|x| x.replace_self_type(self_type)), + .for_each(|x| x.replace_self_type(type_engine, self_type)), CodeBlock(block) => { - block.replace_self_type(self_type); + block.replace_self_type(type_engine, self_type); } FunctionParameter => (), IfExp { @@ -518,16 +536,16 @@ impl ReplaceSelfType for TyExpressionVariant { then, r#else, } => { - condition.replace_self_type(self_type); - then.replace_self_type(self_type); + condition.replace_self_type(type_engine, self_type); + then.replace_self_type(type_engine, self_type); if let Some(ref mut r#else) = r#else { - r#else.replace_self_type(self_type); + r#else.replace_self_type(type_engine, self_type); } } AsmExpression { registers, .. } => { registers .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); } StructFieldAccess { prefix, @@ -535,59 +553,59 @@ impl ReplaceSelfType for TyExpressionVariant { ref mut resolved_type_of_parent, .. } => { - resolved_type_of_parent.replace_self_type(self_type); - field_to_access.replace_self_type(self_type); - prefix.replace_self_type(self_type); + resolved_type_of_parent.replace_self_type(type_engine, self_type); + field_to_access.replace_self_type(type_engine, self_type); + prefix.replace_self_type(type_engine, self_type); } TupleElemAccess { prefix, ref mut resolved_type_of_parent, .. } => { - resolved_type_of_parent.replace_self_type(self_type); - prefix.replace_self_type(self_type); + resolved_type_of_parent.replace_self_type(type_engine, self_type); + prefix.replace_self_type(type_engine, self_type); } EnumInstantiation { enum_decl, contents, .. } => { - enum_decl.replace_self_type(self_type); + enum_decl.replace_self_type(type_engine, self_type); if let Some(ref mut contents) = contents { - contents.replace_self_type(self_type) + contents.replace_self_type(type_engine, self_type) }; } - AbiCast { address, .. } => address.replace_self_type(self_type), + AbiCast { address, .. } => address.replace_self_type(type_engine, self_type), StorageAccess { .. } => (), IntrinsicFunction(kind) => { - kind.replace_self_type(self_type); + kind.replace_self_type(type_engine, self_type); } EnumTag { exp } => { - exp.replace_self_type(self_type); + exp.replace_self_type(type_engine, self_type); } UnsafeDowncast { exp, variant } => { - exp.replace_self_type(self_type); - variant.replace_self_type(self_type); + exp.replace_self_type(type_engine, self_type); + variant.replace_self_type(type_engine, self_type); } AbiName(_) => (), WhileLoop { ref mut condition, ref mut body, } => { - condition.replace_self_type(self_type); - body.replace_self_type(self_type); + condition.replace_self_type(type_engine, self_type); + body.replace_self_type(type_engine, self_type); } Break => (), Continue => (), - Reassignment(reassignment) => reassignment.replace_self_type(self_type), + Reassignment(reassignment) => reassignment.replace_self_type(type_engine, self_type), StorageReassignment(..) => (), - Return(stmt) => stmt.replace_self_type(self_type), + Return(stmt) => stmt.replace_self_type(type_engine, self_type), } } } impl ReplaceDecls for TyExpressionVariant { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping) { + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { use TyExpressionVariant::*; match self { Literal(..) => (), @@ -596,35 +614,35 @@ impl ReplaceDecls for TyExpressionVariant { ref mut arguments, .. } => { - function_decl_id.replace_decls(decl_mapping); + function_decl_id.replace_decls(decl_mapping, type_engine); let new_decl_id = function_decl_id .clone() - .replace_decls_and_insert_new(decl_mapping); + .replace_decls_and_insert_new(decl_mapping, type_engine); function_decl_id.replace_id(*new_decl_id); for (_, arg) in arguments.iter_mut() { - arg.replace_decls(decl_mapping); + arg.replace_decls(decl_mapping, type_engine); } } LazyOperator { lhs, rhs, .. } => { - (*lhs).replace_decls(decl_mapping); - (*rhs).replace_decls(decl_mapping); + (*lhs).replace_decls(decl_mapping, type_engine); + (*rhs).replace_decls(decl_mapping, type_engine); } VariableExpression { .. } => (), Tuple { fields } => fields .iter_mut() - .for_each(|x| x.replace_decls(decl_mapping)), + .for_each(|x| x.replace_decls(decl_mapping, type_engine)), Array { contents } => contents .iter_mut() - .for_each(|x| x.replace_decls(decl_mapping)), + .for_each(|x| x.replace_decls(decl_mapping, type_engine)), ArrayIndex { prefix, index } => { - (*prefix).replace_decls(decl_mapping); - (*index).replace_decls(decl_mapping); + (*prefix).replace_decls(decl_mapping, type_engine); + (*index).replace_decls(decl_mapping, type_engine); } StructExpression { fields, .. } => fields .iter_mut() - .for_each(|x| x.replace_decls(decl_mapping)), + .for_each(|x| x.replace_decls(decl_mapping, type_engine)), CodeBlock(block) => { - block.replace_decls(decl_mapping); + block.replace_decls(decl_mapping, type_engine); } FunctionParameter => (), IfExp { @@ -632,18 +650,18 @@ impl ReplaceDecls for TyExpressionVariant { then, r#else, } => { - condition.replace_decls(decl_mapping); - then.replace_decls(decl_mapping); + condition.replace_decls(decl_mapping, type_engine); + then.replace_decls(decl_mapping, type_engine); if let Some(ref mut r#else) = r#else { - r#else.replace_decls(decl_mapping); + r#else.replace_decls(decl_mapping, type_engine); } } AsmExpression { .. } => {} StructFieldAccess { prefix, .. } => { - prefix.replace_decls(decl_mapping); + prefix.replace_decls(decl_mapping, type_engine); } TupleElemAccess { prefix, .. } => { - prefix.replace_decls(decl_mapping); + prefix.replace_decls(decl_mapping, type_engine); } EnumInstantiation { enum_decl: _, @@ -653,37 +671,37 @@ impl ReplaceDecls for TyExpressionVariant { // TODO: replace enum decl //enum_decl.replace_decls(decl_mapping); if let Some(ref mut contents) = contents { - contents.replace_decls(decl_mapping); + contents.replace_decls(decl_mapping, type_engine); }; } - AbiCast { address, .. } => address.replace_decls(decl_mapping), + AbiCast { address, .. } => address.replace_decls(decl_mapping, type_engine), StorageAccess { .. } => (), IntrinsicFunction(_) => {} EnumTag { exp } => { - exp.replace_decls(decl_mapping); + exp.replace_decls(decl_mapping, type_engine); } UnsafeDowncast { exp, .. } => { - exp.replace_decls(decl_mapping); + exp.replace_decls(decl_mapping, type_engine); } AbiName(_) => (), WhileLoop { ref mut condition, ref mut body, } => { - condition.replace_decls(decl_mapping); - body.replace_decls(decl_mapping); + condition.replace_decls(decl_mapping, type_engine); + body.replace_decls(decl_mapping, type_engine); } Break => (), Continue => (), - Reassignment(reassignment) => reassignment.replace_decls(decl_mapping), + Reassignment(reassignment) => reassignment.replace_decls(decl_mapping, type_engine), StorageReassignment(..) => (), - Return(stmt) => stmt.replace_decls(decl_mapping), + Return(stmt) => stmt.replace_decls(decl_mapping, type_engine), } } } -impl fmt::Display for TyExpressionVariant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl DisplayWithTypeEngine for TyExpressionVariant { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { let s = match self { TyExpressionVariant::Literal(lit) => format!("literal {}", lit), TyExpressionVariant::FunctionApplication { @@ -698,7 +716,7 @@ impl fmt::Display for TyExpressionVariant { TyExpressionVariant::Tuple { fields } => { let fields = fields .iter() - .map(|field| field.to_string()) + .map(|field| type_engine.help_out(field).to_string()) .collect::>() .join(", "); format!("tuple({})", fields) @@ -722,7 +740,7 @@ impl fmt::Display for TyExpressionVariant { } => { format!( "\"{}.{}\" struct field access", - look_up_type_id(*resolved_type_of_parent), + type_engine.help_out(*resolved_type_of_parent), field_to_access.name ) } @@ -733,7 +751,7 @@ impl fmt::Display for TyExpressionVariant { } => { format!( "\"{}.{}\" tuple index", - look_up_type_id(*resolved_type_of_parent), + type_engine.help_out(*resolved_type_of_parent), elem_to_access_num ) } @@ -756,16 +774,20 @@ impl fmt::Display for TyExpressionVariant { TyExpressionVariant::StorageAccess(access) => { format!("storage field {} access", access.storage_field_name()) } - TyExpressionVariant::IntrinsicFunction(kind) => kind.to_string(), + TyExpressionVariant::IntrinsicFunction(kind) => type_engine.help_out(kind).to_string(), TyExpressionVariant::AbiName(n) => format!("ABI name {}", n), TyExpressionVariant::EnumTag { exp } => { - format!("({} as tag)", look_up_type_id(exp.return_type)) + format!("({} as tag)", type_engine.help_out(exp.return_type)) } TyExpressionVariant::UnsafeDowncast { exp, variant } => { - format!("({} as {})", look_up_type_id(exp.return_type), variant.name) + format!( + "({} as {})", + type_engine.help_out(exp.return_type), + variant.name + ) } TyExpressionVariant::WhileLoop { condition, .. } => { - format!("while loop on {}", condition) + format!("while loop on {}", type_engine.help_out(&**condition)) } TyExpressionVariant::Break => "break".to_string(), TyExpressionVariant::Continue => "continue".to_string(), @@ -793,7 +815,7 @@ impl fmt::Display for TyExpressionVariant { format!("storage reassignment to {}", place) } TyExpressionVariant::Return(exp) => { - format!("return {}", *exp) + format!("return {}", type_engine.help_out(&**exp)) } }; write!(f, "{}", s) diff --git a/sway-core/src/language/ty/expression/intrinsic_function.rs b/sway-core/src/language/ty/expression/intrinsic_function.rs index d326356760c..e858cff8ecb 100644 --- a/sway-core/src/language/ty/expression/intrinsic_function.rs +++ b/sway-core/src/language/ty/expression/intrinsic_function.rs @@ -5,7 +5,7 @@ use itertools::Itertools; use sway_ast::Intrinsic; use sway_types::Span; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct TyIntrinsicFunctionKind { pub kind: Intrinsic, pub arguments: Vec, @@ -13,36 +13,49 @@ pub struct TyIntrinsicFunctionKind { pub span: Span, } +impl EqWithTypeEngine for TyIntrinsicFunctionKind {} +impl PartialEqWithTypeEngine for TyIntrinsicFunctionKind { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.kind == rhs.kind + && self.arguments.eq(&rhs.arguments, type_engine) + && self.type_arguments.eq(&rhs.type_arguments, type_engine) + } +} + impl CopyTypes for TyIntrinsicFunctionKind { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { for arg in &mut self.arguments { - arg.copy_types(type_mapping); + arg.copy_types(type_mapping, type_engine); } for targ in &mut self.type_arguments { - targ.type_id.copy_types(type_mapping); + targ.type_id.copy_types(type_mapping, type_engine); } } } impl ReplaceSelfType for TyIntrinsicFunctionKind { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { for arg in &mut self.arguments { - arg.replace_self_type(self_type); + arg.replace_self_type(type_engine, self_type); } for targ in &mut self.type_arguments { - targ.type_id.replace_self_type(self_type); + targ.type_id.replace_self_type(type_engine, self_type); } } } -impl fmt::Display for TyIntrinsicFunctionKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl DisplayWithTypeEngine for TyIntrinsicFunctionKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { let targs = self .type_arguments .iter() - .map(|targ| look_up_type_id(targ.type_id)) + .map(|targ| type_engine.help_out(targ.type_id)) + .join(", "); + let args = self + .arguments + .iter() + .map(|e| format!("{}", type_engine.help_out(e))) .join(", "); - let args = self.arguments.iter().map(|e| format!("{}", e)).join(", "); write!(f, "{}::<{}>::({})", self.kind, targs, args) } diff --git a/sway-core/src/language/ty/expression/reassignment.rs b/sway-core/src/language/ty/expression/reassignment.rs index 136c7bc7df2..1f02c6d7603 100644 --- a/sway-core/src/language/ty/expression/reassignment.rs +++ b/sway-core/src/language/ty/expression/reassignment.rs @@ -8,7 +8,7 @@ use crate::{ type_system::*, }; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct TyReassignment { // either a direct variable, so length of 1, or // at series of struct fields/array indices (array syntax) @@ -18,23 +18,33 @@ pub struct TyReassignment { pub rhs: TyExpression, } +impl EqWithTypeEngine for TyReassignment {} +impl PartialEqWithTypeEngine for TyReassignment { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.lhs_base_name == rhs.lhs_base_name + && self.lhs_type == rhs.lhs_type + && self.lhs_indices == rhs.lhs_indices + && self.rhs.eq(&rhs.rhs, type_engine) + } +} + impl CopyTypes for TyReassignment { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - self.rhs.copy_types(type_mapping); - self.lhs_type.copy_types(type_mapping); + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + self.rhs.copy_types(type_mapping, type_engine); + self.lhs_type.copy_types(type_mapping, type_engine); } } impl ReplaceSelfType for TyReassignment { - fn replace_self_type(&mut self, self_type: TypeId) { - self.rhs.replace_self_type(self_type); - self.lhs_type.replace_self_type(self_type); + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + self.rhs.replace_self_type(type_engine, self_type); + self.lhs_type.replace_self_type(type_engine, self_type); } } impl ReplaceDecls for TyReassignment { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping) { - self.rhs.replace_decls(decl_mapping); + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { + self.rhs.replace_decls(decl_mapping, type_engine); } } @@ -63,13 +73,22 @@ impl ProjectionKind { } /// Describes each field being drilled down into in storage and its type. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct TyStorageReassignment { pub fields: Vec, pub(crate) ix: StateIndex, pub rhs: TyExpression, } +impl EqWithTypeEngine for TyStorageReassignment {} +impl PartialEqWithTypeEngine for TyStorageReassignment { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.fields.eq(&rhs.fields, type_engine) + && self.ix == rhs.ix + && self.rhs.eq(&rhs.rhs, type_engine) + } +} + impl Spanned for TyStorageReassignment { fn span(&self) -> Span { self.fields @@ -91,7 +110,7 @@ impl TyStorageReassignment { /// Describes a single subfield access in the sequence when reassigning to a subfield within /// storage. -#[derive(Clone, Debug, Eq)] +#[derive(Clone, Debug)] pub struct TyStorageReassignDescriptor { pub name: Ident, pub type_id: TypeId, @@ -101,8 +120,12 @@ pub struct TyStorageReassignDescriptor { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TyStorageReassignDescriptor { - fn eq(&self, other: &Self) -> bool { - self.name == other.name && look_up_type_id(self.type_id) == look_up_type_id(other.type_id) +impl EqWithTypeEngine for TyStorageReassignDescriptor {} +impl PartialEqWithTypeEngine for TyStorageReassignDescriptor { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { + self.name == other.name + && type_engine + .look_up_type_id(self.type_id) + .eq(&type_engine.look_up_type_id(other.type_id), type_engine) } } diff --git a/sway-core/src/language/ty/expression/struct_exp_field.rs b/sway-core/src/language/ty/expression/struct_exp_field.rs index 29d098464cc..4dd0bb89786 100644 --- a/sway-core/src/language/ty/expression/struct_exp_field.rs +++ b/sway-core/src/language/ty/expression/struct_exp_field.rs @@ -6,26 +6,33 @@ use crate::{ type_system::*, }; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct TyStructExpressionField { pub name: Ident, pub value: TyExpression, } +impl EqWithTypeEngine for TyStructExpressionField {} +impl PartialEqWithTypeEngine for TyStructExpressionField { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.name == rhs.name && self.value.eq(&rhs.value, type_engine) + } +} + impl CopyTypes for TyStructExpressionField { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - self.value.copy_types(type_mapping); + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + self.value.copy_types(type_mapping, type_engine); } } impl ReplaceSelfType for TyStructExpressionField { - fn replace_self_type(&mut self, self_type: TypeId) { - self.value.replace_self_type(self_type); + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + self.value.replace_self_type(type_engine, self_type); } } impl ReplaceDecls for TyStructExpressionField { - fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping) { - self.value.replace_decls(decl_mapping); + fn replace_decls_inner(&mut self, decl_mapping: &DeclMapping, type_engine: &TypeEngine) { + self.value.replace_decls(decl_mapping, type_engine); } } diff --git a/sway-core/src/language/ty/program.rs b/sway-core/src/language/ty/program.rs index 058ffc2e27b..ed53473742f 100644 --- a/sway-core/src/language/ty/program.rs +++ b/sway-core/src/language/ty/program.rs @@ -22,6 +22,7 @@ pub struct TyProgram { impl TyProgram { /// Validate the root module given the expected program kind. pub fn validate_root( + ty_engine: &TypeEngine, root: &TyModule, kind: parsed::TreeType, module_span: Span, @@ -34,6 +35,7 @@ impl TyProgram { for (_, submodule) in &root.submodules { check!( Self::validate_root( + ty_engine, &submodule.module, parsed::TreeType::Library { name: submodule.library_name.clone(), @@ -86,7 +88,7 @@ impl TyProgram { errors ); if matches!( - look_up_type_id(implementing_for_type_id), + ty_engine.look_up_type_id(implementing_for_type_id), TypeInfo::Contract ) { for method_id in methods { @@ -107,7 +109,10 @@ impl TyProgram { for ast_n in &root.all_nodes { check!( - storage_only_types::validate_decls_for_storage_only_types_in_ast(&ast_n.content), + storage_only_types::validate_decls_for_storage_only_types_in_ast( + ty_engine, + &ast_n.content + ), continue, warnings, errors @@ -156,7 +161,7 @@ impl TyProgram { }); } let main_func = mains.remove(0); - match look_up_type_id(main_func.return_type) { + match ty_engine.look_up_type_id(main_func.return_type) { TypeInfo::Boolean => (), _ => errors.push(CompileError::PredicateMainDoesNotReturnBool( main_func.span.clone(), @@ -181,11 +186,11 @@ impl TyProgram { // Directly returning a `raw_slice` is allowed, which will be just mapped to a RETD. // TODO: Allow returning nested `raw_slice`s when our spec supports encoding DSTs. let main_func = mains.remove(0); - let main_return_type_info = look_up_type_id(main_func.return_type); + let main_return_type_info = ty_engine.look_up_type_id(main_func.return_type); let nested_types = check!( main_return_type_info .clone() - .extract_nested_types(&main_func.return_type_span), + .extract_nested_types(ty_engine, &main_func.return_type_span), vec![], warnings, errors @@ -321,15 +326,16 @@ impl TyProgram { pub fn generate_json_abi_program( &self, + type_engine: &TypeEngine, types: &mut Vec, ) -> JsonABIProgram { match &self.kind { TyProgramKind::Contract { abi_entries, .. } => { let functions = abi_entries .iter() - .map(|x| x.generate_json_abi_function(types)) + .map(|x| x.generate_json_abi_function(type_engine, types)) .collect(); - let logged_types = self.generate_json_logged_types(types); + let logged_types = self.generate_json_logged_types(type_engine, types); JsonABIProgram { types: types.to_vec(), functions, @@ -338,8 +344,8 @@ impl TyProgram { } TyProgramKind::Script { main_function, .. } | TyProgramKind::Predicate { main_function, .. } => { - let functions = vec![main_function.generate_json_abi_function(types)]; - let logged_types = self.generate_json_logged_types(types); + let functions = vec![main_function.generate_json_abi_function(type_engine, types)]; + let logged_types = self.generate_json_logged_types(type_engine, types); JsonABIProgram { types: types.to_vec(), functions, @@ -356,6 +362,7 @@ impl TyProgram { fn generate_json_logged_types( &self, + type_engine: &TypeEngine, types: &mut Vec, ) -> Vec { // A list of all `JsonTypeDeclaration`s needed for the logged types @@ -363,10 +370,10 @@ impl TyProgram { .logged_types .iter() .map(|(_, type_id)| JsonTypeDeclaration { - type_id: **type_id, - type_field: type_id.get_json_type_str(*type_id), - components: type_id.get_json_type_components(types, *type_id), - type_parameters: type_id.get_json_type_parameters(types, *type_id), + type_id: type_id.index(), + type_field: type_id.get_json_type_str(type_engine, *type_id), + components: type_id.get_json_type_components(type_engine, types, *type_id), + type_parameters: type_id.get_json_type_parameters(type_engine, types, *type_id), }) .collect::>(); @@ -380,8 +387,8 @@ impl TyProgram { log_id: **log_id, logged_type: JsonTypeApplication { name: "".to_string(), - type_id: **type_id, - type_arguments: type_id.get_json_type_arguments(types, *type_id), + type_id: type_id.index(), + type_arguments: type_id.get_json_type_arguments(type_engine, types, *type_id), }, }) .collect() diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index 6ea0d10729f..7b8e09c323f 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -40,7 +40,7 @@ use sway_types::{ident::Ident, span, Spanned}; pub use type_system::*; use language::{parsed, ty}; -use transform::to_parsed_lang; +use transform::to_parsed_lang::{self, convert_module_kind}; pub mod fuel_prelude { pub use fuel_vm::{self, fuel_asm, fuel_crypto, fuel_tx, fuel_types}; @@ -53,26 +53,43 @@ pub mod fuel_prelude { /// # use sway_core::parse; /// # fn main() { /// let input = "script; fn main() -> bool { true }"; -/// let result = parse(input.into(), Default::default()); +/// let result = parse(input.into(), &<_>::default(), None); /// # } /// ``` /// /// # Panics /// Panics if the parser panics. -pub fn parse(input: Arc, config: Option<&BuildConfig>) -> CompileResult { +pub fn parse( + input: Arc, + type_engine: &TypeEngine, + config: Option<&BuildConfig>, +) -> CompileResult { CompileResult::with_handler(|h| match config { - None => parse_in_memory(h, input), + None => parse_in_memory(h, type_engine, input), // When a `BuildConfig` is given, // the module source may declare `dep`s that must be parsed from other files. - Some(config) => parse_module_tree(h, input, config.canonical_root_module()) + Some(config) => parse_module_tree(h, type_engine, input, config.canonical_root_module()) .map(|(kind, root)| parsed::ParseProgram { kind, root }), }) } +/// Parses the tree kind in the input provided. +/// +/// This will lex the entire input, but parses only the module kind. +pub fn parse_tree_type(input: Arc) -> CompileResult { + CompileResult::with_handler(|h| { + sway_parse::parse_module_kind(h, input, None).map(|kind| convert_module_kind(&kind)) + }) +} + /// When no `BuildConfig` is given, we're assumed to be parsing in-memory with no submodules. -fn parse_in_memory(handler: &Handler, src: Arc) -> Result { +fn parse_in_memory( + handler: &Handler, + type_engine: &TypeEngine, + src: Arc, +) -> Result { let module = sway_parse::parse_file(handler, src, None)?; - let (kind, tree) = to_parsed_lang::convert_parse_tree(handler, module)?; + let (kind, tree) = to_parsed_lang::convert_parse_tree(handler, type_engine, module)?; let submodules = Default::default(); let root = parsed::ParseModule { tree, submodules }; Ok(parsed::ParseProgram { kind, root }) @@ -81,6 +98,7 @@ fn parse_in_memory(handler: &Handler, src: Arc) -> Result Vec<(Ident, parsed::ParseSubmodule)> { @@ -103,7 +121,9 @@ fn parse_submodules( } }; - if let Ok((kind, module)) = parse_module_tree(handler, dep_str.clone(), dep_path.clone()) { + if let Ok((kind, module)) = + parse_module_tree(handler, type_engine, dep_str.clone(), dep_path.clone()) + { let library_name = match kind { parsed::TreeType::Library { name } => name, _ => { @@ -132,6 +152,7 @@ fn parse_submodules( /// parse this module including all of its submodules. fn parse_module_tree( handler: &Handler, + type_engine: &TypeEngine, src: Arc, path: Arc, ) -> Result<(parsed::TreeType, parsed::ParseModule), ErrorEmitted> { @@ -141,10 +162,10 @@ fn parse_module_tree( // Parse all submodules before converting to the `ParseTree`. // This always recovers on parse errors for the file itself by skipping that file. - let submodules = parse_submodules(handler, &module, module_dir); + let submodules = parse_submodules(handler, type_engine, &module, module_dir); // Convert from the raw parsed module to the `ParseTree` ready for type-check. - let (kind, tree) = to_parsed_lang::convert_parse_tree(handler, module)?; + let (kind, tree) = to_parsed_lang::convert_parse_tree(handler, type_engine, module)?; Ok((kind, parsed::ParseModule { tree, submodules })) } @@ -163,6 +184,7 @@ pub struct CompiledAsm(pub FinalizedAsm); pub struct CompiledBytecode(pub Vec); pub fn parsed_to_ast( + type_engine: &TypeEngine, parse_program: &parsed::ParseProgram, initial_namespace: namespace::Module, ) -> CompileResult { @@ -171,7 +193,7 @@ pub fn parsed_to_ast( value: typed_program_opt, mut warnings, mut errors, - } = ty::TyProgram::type_check(parse_program, initial_namespace); + } = ty::TyProgram::type_check(type_engine, parse_program, initial_namespace); let mut typed_program = match typed_program_opt { Some(typed_program) => typed_program, None => return err(warnings, errors), @@ -182,7 +204,7 @@ pub fn parsed_to_ast( value: types_metadata_result, warnings: new_warnings, errors: new_errors, - } = typed_program.collect_types_metadata(&mut CollectTypesMetadataContext::new()); + } = typed_program.collect_types_metadata(&mut CollectTypesMetadataContext::new(type_engine)); warnings.extend(new_warnings); errors.extend(new_errors); let types_metadata = match types_metadata_result { @@ -198,7 +220,7 @@ pub fn parsed_to_ast( })); // Perform control flow analysis and extend with any errors. - let cfa_res = perform_control_flow_analysis(&typed_program); + let cfa_res = perform_control_flow_analysis(type_engine, &typed_program); errors.extend(cfa_res.errors); warnings.extend(cfa_res.warnings); @@ -208,6 +230,7 @@ pub fn parsed_to_ast( let mut md_mgr = MetadataManager::default(); let module = Module::new(&mut ctx, Kind::Contract); if let Err(e) = ir_generation::compile::compile_constants( + type_engine, &mut ctx, &mut md_mgr, module, @@ -223,6 +246,7 @@ pub fn parsed_to_ast( // Check that all storage initializers can be evaluated at compile time. let typed_wiss_res = typed_program.get_typed_program_with_initialized_storage_slots( + type_engine, &mut ctx, &mut md_mgr, module, @@ -253,6 +277,7 @@ pub fn parsed_to_ast( } pub fn compile_to_ast( + type_engine: &TypeEngine, input: Arc, initial_namespace: namespace::Module, build_config: Option<&BuildConfig>, @@ -262,14 +287,14 @@ pub fn compile_to_ast( value: parse_program_opt, mut warnings, mut errors, - } = parse(input, build_config); + } = parse(input, type_engine, build_config); let parse_program = match parse_program_opt { Some(parse_program) => parse_program, None => return deduped_err(warnings, errors), }; // Type check (+ other static analysis) the CST to a typed AST. - let typed_res = parsed_to_ast(&parse_program, initial_namespace); + let typed_res = parsed_to_ast(type_engine, &parse_program, initial_namespace); errors.extend(typed_res.errors); warnings.extend(typed_res.warnings); let typed_program = match typed_res.value { @@ -288,18 +313,20 @@ pub fn compile_to_ast( /// try compiling to a `CompiledAsm`, /// containing the asm in opcode form (not raw bytes/bytecode). pub fn compile_to_asm( + type_engine: &TypeEngine, input: Arc, initial_namespace: namespace::Module, build_config: BuildConfig, ) -> CompileResult { - let ast_res = compile_to_ast(input, initial_namespace, Some(&build_config)); - ast_to_asm(ast_res, &build_config) + let ast_res = compile_to_ast(type_engine, input, initial_namespace, Some(&build_config)); + ast_to_asm(type_engine, ast_res, &build_config) } /// Given an AST compilation result, /// try compiling to a `CompiledAsm`, /// containing the asm in opcode form (not raw bytes/bytecode). pub fn ast_to_asm( + type_engine: &TypeEngine, ast_res: CompileResult, build_config: &BuildConfig, ) -> CompileResult { @@ -309,7 +336,7 @@ pub fn ast_to_asm( let mut errors = ast_res.errors; let mut warnings = ast_res.warnings; let asm = check!( - compile_ast_to_ir_to_asm(typed_program, build_config), + compile_ast_to_ir_to_asm(type_engine, typed_program, build_config), return deduped_err(warnings, errors), warnings, errors @@ -320,6 +347,7 @@ pub fn ast_to_asm( } pub(crate) fn compile_ast_to_ir_to_asm( + type_engine: &TypeEngine, program: ty::TyProgram, build_config: &BuildConfig, ) -> CompileResult { @@ -338,10 +366,11 @@ pub(crate) fn compile_ast_to_ir_to_asm( // IR phase. let tree_type = program.kind.tree_type(); - let mut ir = match ir_generation::compile_program(program, build_config.include_tests) { - Ok(ir) => ir, - Err(e) => return err(warnings, vec![e]), - }; + let mut ir = + match ir_generation::compile_program(program, build_config.include_tests, type_engine) { + Ok(ir) => ir, + Err(e) => return err(warnings, vec![e]), + }; // Find all the entry points for purity checking and DCE. let entry_point_functions: Vec<::sway_ir::Function> = ir @@ -589,12 +618,13 @@ fn simplify_cfg( /// Given input Sway source code, compile to [CompiledBytecode], containing the asm in bytecode form. pub fn compile_to_bytecode( + type_engine: &TypeEngine, input: Arc, initial_namespace: namespace::Module, build_config: BuildConfig, source_map: &mut SourceMap, ) -> CompileResult { - let asm_res = compile_to_asm(input, initial_namespace, build_config); + let asm_res = compile_to_asm(type_engine, input, initial_namespace, build_config); let result = asm_to_bytecode(asm_res, source_map); clear_lazy_statics(); result @@ -624,15 +654,17 @@ pub fn asm_to_bytecode( } pub fn clear_lazy_statics() { - type_system::clear_type_engine(); declaration_engine::declaration_engine::de_clear(); } /// Given a [ty::TyProgram], which is type-checked Sway source, construct a graph to analyze /// control flow and determine if it is valid. -fn perform_control_flow_analysis(program: &ty::TyProgram) -> CompileResult<()> { - let dca_res = dead_code_analysis(program); - let rpa_errors = return_path_analysis(program); +fn perform_control_flow_analysis( + type_engine: &TypeEngine, + program: &ty::TyProgram, +) -> CompileResult<()> { + let dca_res = dead_code_analysis(type_engine, program); + let rpa_errors = return_path_analysis(type_engine, program); let rpa_res = if rpa_errors.is_empty() { ok((), vec![], vec![]) } else { @@ -645,17 +677,22 @@ fn perform_control_flow_analysis(program: &ty::TyProgram) -> CompileResult<()> { /// code. /// /// Returns the graph that was used for analysis. -fn dead_code_analysis(program: &ty::TyProgram) -> CompileResult { +fn dead_code_analysis( + type_engine: &TypeEngine, + program: &ty::TyProgram, +) -> CompileResult { let mut dead_code_graph = Default::default(); let tree_type = program.kind.tree_type(); - module_dead_code_analysis(&program.root, &tree_type, &mut dead_code_graph).flat_map(|_| { - let warnings = dead_code_graph.find_dead_code(); - ok(dead_code_graph, warnings, vec![]) - }) + module_dead_code_analysis(type_engine, &program.root, &tree_type, &mut dead_code_graph) + .flat_map(|_| { + let warnings = dead_code_graph.find_dead_code(); + ok(dead_code_graph, warnings, vec![]) + }) } /// Recursively collect modules into the given `ControlFlowGraph` ready for dead code analysis. fn module_dead_code_analysis( + type_engine: &TypeEngine, module: &ty::TyModule, tree_type: &parsed::TreeType, graph: &mut ControlFlowGraph, @@ -667,34 +704,46 @@ fn module_dead_code_analysis( .fold(init_res, |res, (_, submodule)| { let name = submodule.library_name.clone(); let tree_type = parsed::TreeType::Library { name }; - res.flat_map(|_| module_dead_code_analysis(&submodule.module, &tree_type, graph)) + res.flat_map(|_| { + module_dead_code_analysis(type_engine, &submodule.module, &tree_type, graph) + }) }); submodules_res.flat_map(|()| { - ControlFlowGraph::append_module_to_dead_code_graph(&module.all_nodes, tree_type, graph) - .map(|_| ok((), vec![], vec![])) - .unwrap_or_else(|error| err(vec![], vec![error])) + ControlFlowGraph::append_module_to_dead_code_graph( + type_engine, + &module.all_nodes, + tree_type, + graph, + ) + .map(|_| ok((), vec![], vec![])) + .unwrap_or_else(|error| err(vec![], vec![error])) }) } -fn return_path_analysis(program: &ty::TyProgram) -> Vec { +fn return_path_analysis(type_engine: &TypeEngine, program: &ty::TyProgram) -> Vec { let mut errors = vec![]; - module_return_path_analysis(&program.root, &mut errors); + module_return_path_analysis(type_engine, &program.root, &mut errors); errors } -fn module_return_path_analysis(module: &ty::TyModule, errors: &mut Vec) { +fn module_return_path_analysis( + type_engine: &TypeEngine, + module: &ty::TyModule, + errors: &mut Vec, +) { for (_, submodule) in &module.submodules { - module_return_path_analysis(&submodule.module, errors); + module_return_path_analysis(type_engine, &submodule.module, errors); } - let graph = ControlFlowGraph::construct_return_path_graph(&module.all_nodes); + let graph = ControlFlowGraph::construct_return_path_graph(type_engine, &module.all_nodes); match graph { - Ok(graph) => errors.extend(graph.analyze_return_paths()), + Ok(graph) => errors.extend(graph.analyze_return_paths(type_engine)), Err(error) => errors.push(error), } } #[test] fn test_basic_prog() { + let type_engine = TypeEngine::default(); let prog = parse( r#" contract; @@ -776,6 +825,7 @@ fn test_basic_prog() { } "# .into(), + &type_engine, None, ); let mut warnings: Vec = Vec::new(); @@ -784,6 +834,7 @@ fn test_basic_prog() { } #[test] fn test_parenthesized() { + let type_engine = TypeEngine::default(); let prog = parse( r#" contract; @@ -793,6 +844,7 @@ fn test_parenthesized() { } "# .into(), + &type_engine, None, ); let mut warnings: Vec = Vec::new(); @@ -804,6 +856,7 @@ fn test_parenthesized() { fn test_unary_ordering() { use crate::language::{self, parsed}; + let type_engine = TypeEngine::default(); let prog = parse( r#" script; @@ -813,6 +866,7 @@ fn test_unary_ordering() { !a && b; }"# .into(), + &type_engine, None, ); let mut warnings: Vec = Vec::new(); diff --git a/sway-core/src/semantic_analysis/ast_node/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index d5f96a97654..be2faa97f85 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -37,7 +37,7 @@ impl ty::TyCodeBlock { .iter() .find_map(|node| { if node.deterministically_aborts() { - Some(insert_type(TypeInfo::Unknown)) + Some(ctx.type_engine.insert_type(TypeInfo::Unknown)) } else { match node { ty::TyAstNode { @@ -52,7 +52,7 @@ impl ty::TyCodeBlock { } } }) - .unwrap_or_else(|| insert_type(TypeInfo::Tuple(Vec::new()))); + .unwrap_or_else(|| ctx.type_engine.insert_type(TypeInfo::Tuple(Vec::new()))); append!(ctx.unify_with_self(block_type, &span), warnings, errors); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index df6fda7f400..51030cf868a 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -57,7 +57,7 @@ impl ty::TyAbiDeclaration { for method in methods.into_iter() { let method = check!( ty::TyFunctionDeclaration::type_check(ctx.by_ref(), method.clone(), true, false), - ty::TyFunctionDeclaration::error(method.clone()), + ty::TyFunctionDeclaration::error(method.clone(), ctx.type_engine), warnings, errors ); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs index 46abc414449..31e73ba62cf 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -18,6 +18,8 @@ impl ty::TyDeclaration { let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + let decl = match decl { parsed::Declaration::VariableDeclaration(parsed::VariableDeclaration { name, @@ -28,12 +30,12 @@ impl ty::TyDeclaration { }) => { let type_ascription = check!( ctx.resolve_type_with_self( - insert_type(type_ascription), + type_engine.insert_type(type_ascription), &type_ascription_span.clone().unwrap_or_else(|| name.span()), EnforceTypeArguments::Yes, None ), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors ); @@ -44,7 +46,7 @@ impl ty::TyDeclaration { let result = ty::TyExpression::type_check(ctx.by_ref(), body); let body = check!( result, - ty::TyExpression::error(name.span()), + ty::TyExpression::error(name.span(), type_engine), warnings, errors ); @@ -71,12 +73,12 @@ impl ty::TyDeclaration { let result = { let type_id = check!( ctx.resolve_type_with_self( - insert_type(type_ascription), + type_engine.insert_type(type_ascription), &span, EnforceTypeArguments::No, None ), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -98,7 +100,7 @@ impl ty::TyDeclaration { let value = check!( result, - ty::TyExpression::error(name.span()), + ty::TyExpression::error(name.span(), type_engine), warnings, errors ); @@ -134,7 +136,7 @@ impl ty::TyDeclaration { } parsed::Declaration::FunctionDeclaration(fn_decl) => { let span = fn_decl.span.clone(); - let mut ctx = ctx.with_type_annotation(insert_type(TypeInfo::Unknown)); + let mut ctx = ctx.with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let fn_decl = check!( ty::TyFunctionDeclaration::type_check(ctx.by_ref(), fn_decl, false, false), return ok(ty::TyDeclaration::ErrorRecovery(span), warnings, errors), @@ -175,7 +177,8 @@ impl ty::TyDeclaration { impl_trait.implementing_for_type_id, &impl_trait.methods, &impl_trait.span, - false + false, + type_engine, ), return err(warnings, errors), warnings, @@ -198,7 +201,8 @@ impl ty::TyDeclaration { impl_trait.implementing_for_type_id, &impl_trait.methods, &impl_trait.span, - true + true, + type_engine, ), return err(warnings, errors), warnings, @@ -256,7 +260,11 @@ impl ty::TyDeclaration { } in fields { let type_id = check!( - ctx.resolve_type_without_self(insert_type(type_info), &name.span(), None), + ctx.resolve_type_without_self( + type_engine.insert_type(type_info), + &name.span(), + None + ), return err(warnings, errors), warnings, errors diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index e4b09268cee..591b4380efe 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -75,7 +75,7 @@ impl ty::TyEnumVariant { ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; - let initial_type_id = insert_type(variant.type_info); + let initial_type_id = ctx.type_engine.insert_type(variant.type_info); let enum_variant_type = check!( ctx.resolve_type_with_self( initial_type_id, @@ -83,7 +83,7 @@ impl ty::TyEnumVariant { EnforceTypeArguments::Yes, None ), - insert_type(TypeInfo::ErrorRecovery), + ctx.type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index efe5fa08bee..47156b43d7d 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -34,6 +34,8 @@ impl ty::TyFunctionDeclaration { purity, } = fn_decl; + let type_engine = ctx.type_engine; + // Warn against non-snake case function names. if !is_snake_case(name.as_str()) { warnings.push(CompileWarning { @@ -75,7 +77,7 @@ impl ty::TyFunctionDeclaration { } // type check the return type - let initial_return_type = insert_type(return_type); + let initial_return_type = type_engine.insert_type(return_type); let return_type = check!( fn_ctx.resolve_type_with_self( initial_return_type, @@ -83,7 +85,7 @@ impl ty::TyFunctionDeclaration { EnforceTypeArguments::Yes, None ), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -102,7 +104,7 @@ impl ty::TyFunctionDeclaration { ty::TyCodeBlock::type_check(fn_ctx, body), ( ty::TyCodeBlock { contents: vec![] }, - insert_type(TypeInfo::ErrorRecovery) + type_engine.insert_type(TypeInfo::ErrorRecovery) ), warnings, errors @@ -162,13 +164,13 @@ impl ty::TyFunctionDeclaration { let mut return_type_namespace = fn_ctx .namespace .implemented_traits - .filter_by_type(function_decl.return_type); + .filter_by_type(function_decl.return_type, type_engine); for type_param in function_decl.type_parameters.iter() { - return_type_namespace.filter_against_type(type_param.type_id); + return_type_namespace.filter_against_type(type_engine, type_param.type_id); } ctx.namespace .implemented_traits - .extend(return_type_namespace); + .extend(return_type_namespace, type_engine); ok(function_decl, warnings, errors) } @@ -178,6 +180,9 @@ impl ty::TyFunctionDeclaration { fn test_function_selector_behavior() { use crate::language::Visibility; use sway_types::{integer_bits::IntegerBits, Ident, Span}; + + let type_engine = TypeEngine::default(); + let decl = ty::TyFunctionDeclaration { purity: Default::default(), name: Ident::new_no_span("foo"), @@ -193,7 +198,7 @@ fn test_function_selector_behavior() { is_contract_call: false, }; - let selector_text = match decl.to_selector_name().value { + let selector_text = match decl.to_selector_name(&type_engine).value { Some(value) => value, _ => panic!("test failure"), }; @@ -210,8 +215,8 @@ fn test_function_selector_behavior() { is_reference: false, is_mutable: false, mutability_span: Span::dummy(), - type_id: crate::type_system::insert_type(TypeInfo::Str(5)), - initial_type_id: crate::type_system::insert_type(TypeInfo::Str(5)), + type_id: type_engine.insert_type(TypeInfo::Str(5)), + initial_type_id: type_engine.insert_type(TypeInfo::Str(5)), type_span: Span::dummy(), }, ty::TyFunctionParameter { @@ -219,8 +224,8 @@ fn test_function_selector_behavior() { is_reference: false, is_mutable: false, mutability_span: Span::dummy(), - type_id: insert_type(TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo)), - initial_type_id: crate::type_system::insert_type(TypeInfo::Str(5)), + type_id: type_engine.insert_type(TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo)), + initial_type_id: type_engine.insert_type(TypeInfo::Str(5)), type_span: Span::dummy(), }, ], @@ -234,7 +239,7 @@ fn test_function_selector_behavior() { is_contract_call: false, }; - let selector_text = match decl.to_selector_name().value { + let selector_text = match decl.to_selector_name(&type_engine).value { Some(value) => value, _ => panic!("test failure"), }; diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs index d09988a28d1..86e4bc7975a 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs @@ -27,7 +27,7 @@ impl ty::TyFunctionParameter { type_span, } = parameter; - let initial_type_id = insert_type(type_info); + let initial_type_id = ctx.type_engine.insert_type(type_info); let type_id = check!( ctx.resolve_type_with_self( @@ -36,7 +36,7 @@ impl ty::TyFunctionParameter { EnforceTypeArguments::Yes, None ), - insert_type(TypeInfo::ErrorRecovery), + ctx.type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -80,17 +80,18 @@ impl ty::TyFunctionParameter { type_span, } = parameter; - let initial_type_id = insert_type(type_info); + let initial_type_id = ctx.type_engine.insert_type(type_info); let type_id = check!( ctx.namespace.resolve_type_with_self( + ctx.type_engine, initial_type_id, - insert_type(TypeInfo::SelfType), + ctx.type_engine.insert_type(TypeInfo::SelfType), &type_span, EnforceTypeArguments::Yes, None ), - insert_type(TypeInfo::ErrorRecovery), + ctx.type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 5e3922c453a..4d98bc6b61e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -29,6 +29,8 @@ impl ty::TyImplTrait { block_span, } = impl_trait; + let type_engine = ctx.type_engine; + // create a namespace for the impl let mut impl_namespace = ctx.namespace.clone(); let mut ctx = ctx.by_ref().scoped(&mut impl_namespace); @@ -63,7 +65,7 @@ impl ty::TyImplTrait { // type check the type that we are implementing for let implementing_for_type_id = check!( ctx.resolve_type_without_self( - insert_type(type_implementing_for), + type_engine.insert_type(type_implementing_for), &type_implementing_for_span, None ), @@ -74,7 +76,8 @@ impl ty::TyImplTrait { // check to see if this type is supported in impl blocks check!( - look_up_type_id(implementing_for_type_id) + type_engine + .look_up_type_id(implementing_for_type_id) .expect_is_supported_in_impl_blocks_self(&type_implementing_for_span), return err(warnings, errors), warnings, @@ -84,6 +87,7 @@ impl ty::TyImplTrait { // check for unconstrained type parameters check!( check_for_unconstrained_type_parameters( + type_engine, &new_impl_type_parameters, &trait_type_arguments, implementing_for_type_id, @@ -98,7 +102,7 @@ impl ty::TyImplTrait { let mut ctx = ctx .with_self_type(implementing_for_type_id) .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let impl_trait = match ctx .namespace @@ -168,10 +172,13 @@ impl ty::TyImplTrait { errors ); - if look_up_type_id(implementing_for_type_id) != TypeInfo::Contract { + if !type_engine + .look_up_type_id(implementing_for_type_id) + .eq(&TypeInfo::Contract, type_engine) + { errors.push(CompileError::ImplAbiForNonContract { span: type_implementing_for_span.clone(), - ty: implementing_for_type_id.to_string(), + ty: type_engine.help_out(implementing_for_type_id).to_string(), }); } @@ -220,6 +227,7 @@ impl ty::TyImplTrait { // impl_typ can only be a storage type. // This is noted down in the type engine. fn gather_storage_only_types( + type_engine: &TypeEngine, impl_typ: TypeId, methods: &[ty::TyFunctionDeclaration], access_span: &Span, @@ -386,7 +394,7 @@ impl ty::TyImplTrait { let contains_get_storage_index = codeblock_contains_get_storage_index(&method.body, access_span)?; if contains_get_storage_index { - set_type_as_storage_only(impl_typ); + type_engine.set_type_as_storage_only(impl_typ); return Ok(()); } } @@ -409,6 +417,8 @@ impl ty::TyImplTrait { block_span, } = impl_self; + let type_engine = ctx.type_engine; + // create the namespace for the impl let mut impl_namespace = ctx.namespace.clone(); let mut ctx = ctx.scoped(&mut impl_namespace); @@ -446,7 +456,7 @@ impl ty::TyImplTrait { // type check the type that we are implementing for let implementing_for_type_id = check!( ctx.resolve_type_without_self( - insert_type(type_implementing_for), + type_engine.insert_type(type_implementing_for), &type_implementing_for_span, None ), @@ -457,7 +467,8 @@ impl ty::TyImplTrait { // check to see if this type is supported in impl blocks check!( - look_up_type_id(implementing_for_type_id) + type_engine + .look_up_type_id(implementing_for_type_id) .expect_is_supported_in_impl_blocks_self(&type_implementing_for_span), return err(warnings, errors), warnings, @@ -467,6 +478,7 @@ impl ty::TyImplTrait { // check for unconstrained type parameters check!( check_for_unconstrained_type_parameters( + type_engine, &new_impl_type_parameters, &[], implementing_for_type_id, @@ -480,7 +492,7 @@ impl ty::TyImplTrait { let mut ctx = ctx .with_self_type(implementing_for_type_id) .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); // type check the methods inside of the impl block let mut methods = vec![]; @@ -498,6 +510,7 @@ impl ty::TyImplTrait { check!( CompileResult::from(Self::gather_storage_only_types( + type_engine, implementing_for_type_id, &methods, &type_implementing_for_span, @@ -544,6 +557,7 @@ fn type_check_trait_implementation( let mut errors = vec![]; let mut warnings = vec![]; + let type_engine = ctx.type_engine; let self_type = ctx.self_type(); let interface_name = || -> InterfaceName { if is_contract { @@ -564,7 +578,8 @@ fn type_check_trait_implementation( .iter() .map(|x| x.into()) .collect::>(), - block_span + block_span, + type_engine, ), return err(warnings, errors), warnings, @@ -594,6 +609,7 @@ fn type_check_trait_implementation( .collect::>(), &trait_name.span(), false, + type_engine, ); // This map keeps track of the remaining functions in the interface surface @@ -624,7 +640,7 @@ fn type_check_trait_implementation( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); // type check the function declaration let mut impl_method = check!( @@ -658,7 +674,7 @@ fn type_check_trait_implementation( // replace instances of `TypeInfo::SelfType` with a fresh // `TypeInfo::SelfType` to avoid replacing types in the original trait // declaration - impl_method_signature.replace_self_type(ctx.self_type()); + impl_method_signature.replace_self_type(type_engine, ctx.self_type()); // ensure this fn decl's parameters and signature lines up with the one // in the trait @@ -699,7 +715,7 @@ fn type_check_trait_implementation( }); } - let (new_warnings, new_errors) = unify_right_with_self( + let (new_warnings, new_errors) = type_engine.unify_right_with_self( impl_method_param.type_id, impl_method_signature_param.type_id, ctx.self_type(), @@ -710,8 +726,10 @@ fn type_check_trait_implementation( errors.push(CompileError::MismatchedTypeInInterfaceSurface { interface_name: interface_name(), span: impl_method_param.type_span.clone(), - given: impl_method_param.type_id.to_string(), - expected: impl_method_signature_param.type_id.to_string(), + given: type_engine.help_out(impl_method_param.type_id).to_string(), + expected: type_engine + .help_out(impl_method_signature_param.type_id) + .to_string(), }); continue; } @@ -739,7 +757,7 @@ fn type_check_trait_implementation( // unify the return type of the implemented function and the return // type of the signature - let (new_warnings, new_errors) = unify_right_with_self( + let (new_warnings, new_errors) = type_engine.unify_right_with_self( impl_method.return_type, impl_method_signature.return_type, ctx.self_type(), @@ -750,8 +768,10 @@ fn type_check_trait_implementation( errors.push(CompileError::MismatchedTypeInInterfaceSurface { interface_name: interface_name(), span: impl_method.return_type_span.clone(), - expected: impl_method_signature.return_type.to_string(), - given: impl_method.return_type.to_string(), + expected: type_engine + .help_out(impl_method_signature.return_type) + .to_string(), + given: type_engine.help_out(impl_method.return_type).to_string(), }); continue; } @@ -770,22 +790,27 @@ fn type_check_trait_implementation( // // *This will change* when either https://github.com/FuelLabs/sway/issues/1267 // or https://github.com/FuelLabs/sway/issues/2814 goes in. - let unconstrained_type_parameters_in_this_function: HashSet = impl_method - .unconstrained_type_parameters(impl_type_parameters) + let unconstrained_type_parameters_in_this_function: HashSet< + WithTypeEngine<'_, TypeParameter>, + > = impl_method + .unconstrained_type_parameters(type_engine, impl_type_parameters) .into_iter() .cloned() + .map(|x| WithTypeEngine::new(x, type_engine)) .collect(); - let unconstrained_type_parameters_in_the_type: HashSet = ctx - .self_type() - .unconstrained_type_parameters(impl_type_parameters) - .into_iter() - .cloned() - .collect::>(); + let unconstrained_type_parameters_in_the_type: HashSet> = + ctx.self_type() + .unconstrained_type_parameters(type_engine, impl_type_parameters) + .into_iter() + .cloned() + .map(|x| WithTypeEngine::new(x, type_engine)) + .collect::>(); let mut unconstrained_type_parameters_to_be_added = unconstrained_type_parameters_in_this_function .difference(&unconstrained_type_parameters_in_the_type) .cloned() .into_iter() + .map(|x| x.thing) .collect::>(); impl_method .type_parameters @@ -825,9 +850,9 @@ fn type_check_trait_implementation( warnings, errors ); - method.replace_decls(&decl_mapping); - method.copy_types(&type_mapping); - method.replace_self_type(ctx.self_type()); + method.replace_decls(&decl_mapping, type_engine); + method.copy_types(&type_mapping, ctx.type_engine); + method.replace_self_type(type_engine, ctx.self_type()); all_method_ids.push(de_insert_function(method).with_parent(decl_id.clone())); } @@ -885,6 +910,7 @@ fn type_check_trait_implementation( /// } /// ``` fn check_for_unconstrained_type_parameters( + type_engine: &TypeEngine, type_parameters: &[TypeParameter], trait_type_arguments: &[TypeArgument], self_type: TypeId, @@ -894,24 +920,29 @@ fn check_for_unconstrained_type_parameters( let mut errors = vec![]; // create a list of defined generics, with the generic and a span - let mut defined_generics: HashMap = HashMap::from_iter( + let mut defined_generics: HashMap<_, _> = HashMap::from_iter( type_parameters .iter() - .map(|x| (look_up_type_id(x.type_id), x.span())), + .map(|x| (type_engine.look_up_type_id(x.type_id), x.span())) + .map(|(thing, sp)| (WithTypeEngine::new(thing, type_engine), sp)), ); // create a list of the generics in use in the impl signature let mut generics_in_use = HashSet::new(); for type_arg in trait_type_arguments.iter() { generics_in_use.extend(check!( - look_up_type_id(type_arg.type_id).extract_nested_generics(&type_arg.span), + type_engine + .look_up_type_id(type_arg.type_id) + .extract_nested_generics(type_engine, &type_arg.span), HashSet::new(), warnings, errors )); } generics_in_use.extend(check!( - look_up_type_id(self_type).extract_nested_generics(self_type_span), + type_engine + .look_up_type_id(self_type) + .extract_nested_generics(type_engine, self_type_span), HashSet::new(), warnings, errors diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs index e6b036b5483..feb48b39cb7 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs @@ -6,6 +6,7 @@ use crate::{ }, language::ty, metadata::MetadataManager, + TypeEngine, }; use sway_error::error::CompileError; use sway_ir::{Context, Module}; @@ -14,6 +15,7 @@ use sway_types::state::StateIndex; impl ty::TyStorageDeclaration { pub(crate) fn get_initialized_storage_slots( &self, + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -24,7 +26,13 @@ impl ty::TyStorageDeclaration { .iter() .enumerate() .map(|(i, f)| { - f.get_initialized_storage_slots(context, md_mgr, module, &StateIndex::new(i)) + f.get_initialized_storage_slots( + type_engine, + context, + md_mgr, + module, + &StateIndex::new(i), + ) }) .filter_map(|s| s.map_err(|e| errors.push(e)).ok()) .flatten() @@ -40,12 +48,14 @@ impl ty::TyStorageDeclaration { impl ty::TyStorageField { pub(crate) fn get_initialized_storage_slots( &self, + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, ix: &StateIndex, ) -> Result, CompileError> { compile_constant_expression_to_constant( + type_engine, context, md_mgr, module, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 3cea400ec36..df0369add3d 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -76,7 +76,7 @@ impl ty::TyStructField { pub(crate) fn type_check(mut ctx: TypeCheckContext, field: StructField) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; - let initial_type_id = insert_type(field.type_info); + let initial_type_id = ctx.type_engine.insert_type(field.type_info); let r#type = check!( ctx.resolve_type_with_self( initial_type_id, @@ -84,7 +84,7 @@ impl ty::TyStructField { EnforceTypeArguments::Yes, None ), - insert_type(TypeInfo::ErrorRecovery), + ctx.type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 83cc366a03c..ce79ef79b9e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -40,7 +40,7 @@ impl ty::TyTraitDeclaration { } // A temporary namespace for checking within the trait's scope. - let self_type = insert_type(TypeInfo::SelfType); + let self_type = ctx.type_engine.insert_type(TypeInfo::SelfType); let mut trait_namespace = ctx.namespace.clone(); let mut ctx = ctx.scoped(&mut trait_namespace).with_self_type(self_type); @@ -93,7 +93,8 @@ impl ty::TyTraitDeclaration { self_type, &dummy_interface_surface, &span, - false + false, + ctx.type_engine, ), return err(warnings, errors), warnings, @@ -105,7 +106,7 @@ impl ty::TyTraitDeclaration { for method in methods.into_iter() { let method = check!( ty::TyFunctionDeclaration::type_check(ctx.by_ref(), method.clone(), true, false), - ty::TyFunctionDeclaration::error(method), + ty::TyFunctionDeclaration::error(method, ctx.type_engine), warnings, errors ); @@ -158,7 +159,7 @@ impl ty::TyTraitDeclaration { // Retrieve the implemented methods for this type. for decl_id in ctx .namespace - .get_methods_for_type_and_trait_name(type_id, call_path) + .get_methods_for_type_and_trait_name(ctx.type_engine, type_id, call_path) .into_iter() { let method = check!( @@ -235,7 +236,7 @@ impl ty::TyTraitDeclaration { ); for decl_id in ctx .namespace - .get_methods_for_type_and_trait_name(type_id, call_path) + .get_methods_for_type_and_trait_name(ctx.type_engine, type_id, call_path) .into_iter() { let mut method = check!( @@ -244,7 +245,7 @@ impl ty::TyTraitDeclaration { warnings, errors ); - method.copy_types(&type_mapping); + method.copy_types(&type_mapping, ctx.type_engine); impld_method_ids.insert( method.name.clone(), de_insert_function(method).with_parent(decl_id), @@ -268,6 +269,8 @@ impl ty::TyTraitDeclaration { let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + let ty::TyTraitDeclaration { interface_surface, methods, @@ -297,8 +300,8 @@ impl ty::TyTraitDeclaration { warnings, errors ); - method.replace_self_type(type_id); - method.copy_types(&type_mapping); + method.replace_self_type(type_engine, type_id); + method.copy_types(&type_mapping, type_engine); all_methods.push( de_insert_function(method.to_dummy_func(Mode::NonAbi)).with_parent(decl_id.clone()), ); @@ -310,8 +313,8 @@ impl ty::TyTraitDeclaration { warnings, errors ); - method.replace_self_type(type_id); - method.copy_types(&type_mapping); + method.replace_self_type(type_engine, type_id); + method.copy_types(&type_mapping, type_engine); all_methods.push(de_insert_function(method).with_parent(decl_id.clone())); } @@ -326,6 +329,7 @@ impl ty::TyTraitDeclaration { &all_methods, &trait_name.span(), false, + type_engine, ); if errors.is_empty() { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index a82f39a6df2..2a0913438cb 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -24,6 +24,8 @@ impl ty::TyTraitFn { attributes, } = trait_fn; + let type_engine = ctx.type_engine; + // Create a namespace for the trait function. let mut fn_namespace = ctx.namespace.clone(); let mut fn_ctx = ctx.by_ref().scoped(&mut fn_namespace).with_purity(purity); @@ -44,12 +46,12 @@ impl ty::TyTraitFn { // Type check the return type. let return_type = check!( fn_ctx.resolve_type_with_self( - insert_type(return_type), + type_engine.insert_type(return_type), &return_type_span, EnforceTypeArguments::Yes, None ), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -65,12 +67,13 @@ impl ty::TyTraitFn { // Retrieve the implemented traits for the type of the return type and // insert them in the broader namespace. - ctx.namespace.implemented_traits.extend( - fn_ctx - .namespace - .implemented_traits - .filter_by_type(trait_fn.return_type), - ); + let trait_map = fn_ctx + .namespace + .implemented_traits + .filter_by_type(trait_fn.return_type, type_engine); + ctx.namespace + .implemented_traits + .extend(trait_map, type_engine); ok(trait_fn, warnings, errors) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index d4be90ebc2c..2930a8497cd 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -65,6 +65,8 @@ fn type_check_size_of_val( _type_arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; @@ -78,7 +80,7 @@ fn type_check_size_of_val( } let ctx = ctx .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let exp = check!( ty::TyExpression::type_check(ctx, arguments[0].clone()), return err(warnings, errors), @@ -91,7 +93,7 @@ fn type_check_size_of_val( type_arguments: vec![], span, }; - let return_type = insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); + let return_type = type_engine.insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); ok((intrinsic_function, return_type), warnings, errors) } @@ -105,6 +107,8 @@ fn type_check_size_of_type( type_arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; @@ -126,15 +130,19 @@ fn type_check_size_of_type( } let targ = type_arguments[0].clone(); let initial_type_info = check!( - CompileResult::from(to_typeinfo(targ.type_id, &targ.span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors ); - let initial_type_id = insert_type(initial_type_info); + let initial_type_id = type_engine.insert_type(initial_type_info); let type_id = check!( ctx.resolve_type_with_self(initial_type_id, &targ.span, EnforceTypeArguments::Yes, None), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -148,7 +156,7 @@ fn type_check_size_of_type( }], span, }; - let return_type = insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); + let return_type = type_engine.insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); ok((intrinsic_function, return_type), warnings, errors) } @@ -162,6 +170,8 @@ fn type_check_is_reference_type( type_arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; @@ -175,15 +185,19 @@ fn type_check_is_reference_type( } let targ = type_arguments[0].clone(); let initial_type_info = check!( - CompileResult::from(to_typeinfo(targ.type_id, &targ.span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors ); - let initial_type_id = insert_type(initial_type_info); + let initial_type_id = type_engine.insert_type(initial_type_info); let type_id = check!( ctx.resolve_type_with_self(initial_type_id, &targ.span, EnforceTypeArguments::Yes, None), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -198,7 +212,10 @@ fn type_check_is_reference_type( span, }; ok( - (intrinsic_function, insert_type(TypeInfo::Boolean)), + ( + intrinsic_function, + type_engine.insert_type(TypeInfo::Boolean), + ), warnings, errors, ) @@ -209,12 +226,14 @@ fn type_check_is_reference_type( /// method on that `struct`. /// Constraints: None. fn type_check_get_storage_key( - mut _ctx: TypeCheckContext, + ctx: TypeCheckContext, kind: sway_ast::Intrinsic, _arguments: Vec, _type_arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + ok( ( ty::TyIntrinsicFunctionKind { @@ -223,7 +242,7 @@ fn type_check_get_storage_key( type_arguments: vec![], span, }, - insert_type(TypeInfo::B256), + type_engine.insert_type(TypeInfo::B256), ), vec![], vec![], @@ -239,6 +258,8 @@ fn type_check_eq( arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; if arguments.len() != 2 { @@ -251,7 +272,7 @@ fn type_check_eq( } let mut ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let lhs = arguments[0].clone(); let lhs = check!( @@ -263,7 +284,11 @@ fn type_check_eq( // Check for supported argument types let arg_ty = check!( - CompileResult::from(to_typeinfo(lhs.return_type, &lhs.span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(lhs.return_type, &lhs.span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors @@ -300,7 +325,7 @@ fn type_check_eq( type_arguments: vec![], span, }, - insert_type(TypeInfo::Boolean), + type_engine.insert_type(TypeInfo::Boolean), ), warnings, errors, @@ -320,6 +345,8 @@ fn type_check_gtf( type_arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; @@ -344,7 +371,7 @@ fn type_check_gtf( // Type check the first argument which is the index let mut ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let index = check!( ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), return err(warnings, errors), @@ -355,7 +382,7 @@ fn type_check_gtf( // Type check the second argument which is the tx field ID let mut ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let tx_field_id = check!( ty::TyExpression::type_check(ctx.by_ref(), arguments[1].clone()), return err(warnings, errors), @@ -366,7 +393,9 @@ fn type_check_gtf( // Make sure that the index argument is a `u64` let index_type_info = check!( CompileResult::from( - to_typeinfo(index.return_type, &index.span).map_err(CompileError::from) + type_engine + .to_typeinfo(index.return_type, &index.span) + .map_err(CompileError::from) ), TypeInfo::ErrorRecovery, warnings, @@ -386,7 +415,9 @@ fn type_check_gtf( // Make sure that the tx field ID is a `u64` let tx_field_type_info = check!( CompileResult::from( - to_typeinfo(tx_field_id.return_type, &tx_field_id.span).map_err(CompileError::from) + type_engine + .to_typeinfo(tx_field_id.return_type, &tx_field_id.span) + .map_err(CompileError::from) ), TypeInfo::ErrorRecovery, warnings, @@ -405,15 +436,19 @@ fn type_check_gtf( let targ = type_arguments[0].clone(); let initial_type_info = check!( - CompileResult::from(to_typeinfo(targ.type_id, &targ.span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors ); - let initial_type_id = insert_type(initial_type_info); + let initial_type_id = type_engine.insert_type(initial_type_info); let type_id = check!( ctx.resolve_type_with_self(initial_type_id, &targ.span, EnforceTypeArguments::Yes, None), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -446,6 +481,8 @@ fn type_check_addr_of( arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; @@ -459,7 +496,7 @@ fn type_check_addr_of( } let ctx = ctx .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let exp = check!( ty::TyExpression::type_check(ctx, arguments[0].clone()), return err(warnings, errors), @@ -467,7 +504,11 @@ fn type_check_addr_of( errors ); let copy_type_info = check!( - CompileResult::from(to_typeinfo(exp.return_type, &span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(exp.return_type, &span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors @@ -487,7 +528,7 @@ fn type_check_addr_of( type_arguments: vec![], span, }; - let return_type = insert_type(TypeInfo::RawUntypedPtr); + let return_type = type_engine.insert_type(TypeInfo::RawUntypedPtr); ok((intrinsic_function, return_type), warnings, errors) } @@ -500,6 +541,8 @@ fn type_check_state_load_word( arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; if arguments.len() != 1 { @@ -512,7 +555,7 @@ fn type_check_state_load_word( } let ctx = ctx .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let exp = check!( ty::TyExpression::type_check(ctx, arguments[0].clone()), return err(warnings, errors), @@ -520,12 +563,16 @@ fn type_check_state_load_word( errors ); let key_ty = check!( - CompileResult::from(to_typeinfo(exp.return_type, &span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(exp.return_type, &span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors ); - if key_ty != TypeInfo::B256 { + if !key_ty.eq(&TypeInfo::B256, type_engine) { errors.push(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span, @@ -539,7 +586,7 @@ fn type_check_state_load_word( type_arguments: vec![], span, }; - let return_type = insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); + let return_type = type_engine.insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)); ok((intrinsic_function, return_type), warnings, errors) } @@ -562,6 +609,8 @@ fn type_check_state_store_or_quad( type_arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; if arguments.len() != 2 { @@ -582,7 +631,7 @@ fn type_check_state_store_or_quad( } let mut ctx = ctx .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let key_exp = check!( ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), return err(warnings, errors), @@ -590,12 +639,16 @@ fn type_check_state_store_or_quad( errors ); let key_ty = check!( - CompileResult::from(to_typeinfo(key_exp.return_type, &span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(key_exp.return_type, &span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors ); - if key_ty != TypeInfo::B256 { + if !key_ty.eq(&TypeInfo::B256, type_engine) { errors.push(CompileError::IntrinsicUnsupportedArgType { name: kind.to_string(), span, @@ -605,7 +658,7 @@ fn type_check_state_store_or_quad( } let mut ctx = ctx .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let val_exp = check!( ty::TyExpression::type_check(ctx.by_ref(), arguments[1].clone()), return err(warnings, errors), @@ -615,14 +668,18 @@ fn type_check_state_store_or_quad( let type_argument = type_arguments.get(0).map(|targ| { let mut ctx = ctx .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let initial_type_info = check!( - CompileResult::from(to_typeinfo(targ.type_id, &targ.span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors ); - let initial_type_id = insert_type(initial_type_info); + let initial_type_id = type_engine.insert_type(initial_type_info); let type_id = check!( ctx.resolve_type_with_self( initial_type_id, @@ -630,7 +687,7 @@ fn type_check_state_store_or_quad( EnforceTypeArguments::Yes, None ), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -646,7 +703,7 @@ fn type_check_state_store_or_quad( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }; - let return_type = insert_type(TypeInfo::Tuple(vec![])); + let return_type = type_engine.insert_type(TypeInfo::Tuple(vec![])); ok((intrinsic_function, return_type), warnings, errors) } @@ -659,6 +716,8 @@ fn type_check_log( arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; @@ -673,7 +732,7 @@ fn type_check_log( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let exp = check!( ty::TyExpression::type_check(ctx, arguments[0].clone()), return err(warnings, errors), @@ -686,7 +745,7 @@ fn type_check_log( type_arguments: vec![], span, }; - let return_type = insert_type(TypeInfo::Tuple(vec![])); + let return_type = type_engine.insert_type(TypeInfo::Tuple(vec![])); ok((intrinsic_function, return_type), warnings, errors) } @@ -712,6 +771,8 @@ fn type_check_binary_op( type_arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; @@ -734,7 +795,7 @@ fn type_check_binary_op( let mut ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let lhs = arguments[0].clone(); let lhs = check!( @@ -746,7 +807,11 @@ fn type_check_binary_op( // Check for supported argument types let arg_ty = check!( - CompileResult::from(to_typeinfo(lhs.return_type, &lhs.span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(lhs.return_type, &lhs.span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors @@ -780,7 +845,7 @@ fn type_check_binary_op( type_arguments: vec![], span, }, - insert_type(arg_ty), + type_engine.insert_type(arg_ty), ), warnings, errors, @@ -797,6 +862,8 @@ fn type_check_revert( type_arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; @@ -821,7 +888,7 @@ fn type_check_revert( // Type check the argument which is the revert code let mut ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let revert_code = check!( ty::TyExpression::type_check(ctx.by_ref(), arguments[0].clone()), return err(warnings, errors), @@ -831,7 +898,9 @@ fn type_check_revert( // Make sure that the revert code is a `u64` if !matches!( - to_typeinfo(revert_code.return_type, &revert_code.span).unwrap(), + type_engine + .to_typeinfo(revert_code.return_type, &revert_code.span) + .unwrap(), TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) ) { errors.push(CompileError::IntrinsicUnsupportedArgType { @@ -849,8 +918,8 @@ fn type_check_revert( type_arguments: vec![], span, }, - insert_type(TypeInfo::Unknown), // TODO: change this to the `Never` type when - // available + type_engine.insert_type(TypeInfo::Unknown), // TODO: change this to the `Never` type when + // available ), warnings, errors, @@ -871,6 +940,8 @@ fn type_check_ptr_ops( type_arguments: Vec, span: Span, ) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { + let type_engine = ctx.type_engine; + let mut warnings = vec![]; let mut errors = vec![]; @@ -892,22 +963,26 @@ fn type_check_ptr_ops( } let targ = type_arguments[0].clone(); let initial_type_info = check!( - CompileResult::from(to_typeinfo(targ.type_id, &targ.span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(targ.type_id, &targ.span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors ); - let initial_type_id = insert_type(initial_type_info); + let initial_type_id = type_engine.insert_type(initial_type_info); let type_id = check!( ctx.resolve_type_with_self(initial_type_id, &targ.span, EnforceTypeArguments::No, None), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); let mut ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let lhs = arguments[0].clone(); let lhs = check!( @@ -919,7 +994,11 @@ fn type_check_ptr_ops( // Check for supported argument types let lhs_ty = check!( - CompileResult::from(to_typeinfo(lhs.return_type, &lhs.span).map_err(CompileError::from)), + CompileResult::from( + type_engine + .to_typeinfo(lhs.return_type, &lhs.span) + .map_err(CompileError::from) + ), TypeInfo::ErrorRecovery, warnings, errors @@ -937,9 +1016,9 @@ fn type_check_ptr_ops( let ctx = ctx .by_ref() .with_help_text("Incorrect argument type") - .with_type_annotation(insert_type(TypeInfo::UnsignedInteger( - IntegerBits::SixtyFour, - ))); + .with_type_annotation( + type_engine.insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + ); let rhs = check!( ty::TyExpression::type_check(ctx, rhs), return err(warnings, errors), @@ -959,7 +1038,7 @@ fn type_check_ptr_ops( }], span, }, - insert_type(lhs_ty), + type_engine.insert_type(lhs_ty), ), warnings, errors, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs index 614e21406a4..6f420508724 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/constructor_factory.rs @@ -3,12 +3,7 @@ use std::collections::HashSet; use sway_error::error::CompileError; use sway_types::{Ident, Span}; -use crate::{ - error::*, - language::ty, - type_system::{look_up_type_id, TypeId}, - TypeInfo, -}; +use crate::{error::*, language::ty, type_system::TypeId, TypeEngine, TypeInfo}; use super::{ patstack::PatStack, @@ -21,11 +16,17 @@ pub(crate) struct ConstructorFactory { } impl ConstructorFactory { - pub(crate) fn new(type_id: TypeId, span: &Span) -> CompileResult { + pub(crate) fn new( + type_engine: &TypeEngine, + type_id: TypeId, + span: &Span, + ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; let possible_types = check!( - look_up_type_id(type_id).extract_nested_types(span), + type_engine + .look_up_type_id(type_id) + .extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -73,6 +74,7 @@ impl ConstructorFactory { /// ``` pub(crate) fn create_pattern_not_present( &self, + type_engine: &TypeEngine, sigma: PatStack, span: &Span, ) -> CompileResult { @@ -289,7 +291,7 @@ impl ConstructorFactory { errors ); let (enum_name, enum_variants) = check!( - type_info.expect_enum("", span), + type_info.expect_enum(type_engine, "", span), return err(warnings, errors), warnings, errors @@ -394,6 +396,7 @@ impl ConstructorFactory { /// from the "`Tuple` with 2 sub-patterns" type. pub(crate) fn is_complete_signature( &self, + type_engine: &TypeEngine, pat_stack: &PatStack, span: &Span, ) -> CompileResult { @@ -526,7 +529,7 @@ impl ConstructorFactory { errors ); let (enum_name, enum_variants) = check!( - type_info.expect_enum("", span), + type_info.expect_enum(type_engine, "", span), return err(warnings, errors), warnings, errors diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs index 3bde30f54c9..b291a6f772e 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/usefulness.rs @@ -5,7 +5,7 @@ use crate::{ error::{err, ok}, language::ty, type_system::TypeId, - CompileResult, + CompileResult, TypeEngine, }; use super::{ @@ -198,6 +198,7 @@ use super::{ /// exhaustive if the imaginary additional wildcard pattern has an empty /// `WitnessReport`. pub(crate) fn check_match_expression_usefulness( + type_engine: &TypeEngine, type_id: TypeId, scrutinees: Vec, span: Span, @@ -207,7 +208,7 @@ pub(crate) fn check_match_expression_usefulness( let mut matrix = Matrix::empty(); let mut arms_reachability = vec![]; let factory = check!( - ConstructorFactory::new(type_id, &span), + ConstructorFactory::new(type_engine, type_id, &span), return err(warnings, errors), warnings, errors @@ -221,7 +222,7 @@ pub(crate) fn check_match_expression_usefulness( ); let v = PatStack::from_pattern(pat); let witness_report = check!( - is_useful(&factory, &matrix, &v, &span), + is_useful(type_engine, &factory, &matrix, &v, &span), return err(warnings, errors), warnings, errors @@ -235,7 +236,7 @@ pub(crate) fn check_match_expression_usefulness( } let v = PatStack::from_pattern(Pattern::wild_pattern()); let witness_report = check!( - is_useful(&factory, &matrix, &v, &span), + is_useful(type_engine, &factory, &matrix, &v, &span), return err(warnings, errors), warnings, errors @@ -258,6 +259,7 @@ pub(crate) fn check_match_expression_usefulness( /// pattern, or-pattern, or constructed pattern we do something different. Each /// case returns a witness report that we propogate through the recursive steps. fn is_useful( + type_engine: &TypeEngine, factory: &ConstructorFactory, p: &Matrix, q: &PatStack, @@ -282,19 +284,19 @@ fn is_useful( ); let witness_report = match c { Pattern::Wildcard => check!( - is_useful_wildcard(factory, p, q, span), + is_useful_wildcard(type_engine, factory, p, q, span), return err(warnings, errors), warnings, errors ), Pattern::Or(pats) => check!( - is_useful_or(factory, p, q, pats, span), + is_useful_or(type_engine, factory, p, q, pats, span), return err(warnings, errors), warnings, errors ), c => check!( - is_useful_constructed(factory, p, q, c, span), + is_useful_constructed(type_engine, factory, p, q, c, span), return err(warnings, errors), warnings, errors @@ -343,6 +345,7 @@ fn is_useful( /// 5. Add this new pattern to the resulting witness report /// 6. Return the witness report fn is_useful_wildcard( + type_engine: &TypeEngine, factory: &ConstructorFactory, p: &Matrix, q: &PatStack, @@ -362,7 +365,7 @@ fn is_useful_wildcard( // 2. Determine if Σ is a complete signature. let is_complete_signature = check!( - factory.is_complete_signature(&sigma, span), + factory.is_complete_signature(type_engine, &sigma, span), return err(warnings, errors), warnings, errors @@ -399,7 +402,7 @@ fn is_useful_wildcard( // 3.3. Recursively compute U(S(câ‚–, P), S(câ‚–, q)) let wr = check!( - is_useful(factory, &s_c_k_p, &s_c_k_q, span), + is_useful(type_engine, factory, &s_c_k_p, &s_c_k_q, span), return err(warnings, errors), warnings, errors @@ -482,7 +485,7 @@ fn is_useful_wildcard( // 4.3. Recursively compute *U(D(P), q')*. let mut witness_report = check!( - is_useful(factory, &d_p, &q_rest, span), + is_useful(type_engine, factory, &d_p, &q_rest, span), return err(warnings, errors), warnings, errors @@ -493,7 +496,7 @@ fn is_useful_wildcard( Pattern::Wildcard } else { check!( - factory.create_pattern_not_present(sigma, span), + factory.create_pattern_not_present(type_engine, sigma, span), return err(warnings, errors), warnings, errors @@ -529,6 +532,7 @@ fn is_useful_wildcard( /// 2. Extract the specialized `Matrix` *S(c, q)* /// 3. Recursively compute *U(S(c, P), S(c, q))* fn is_useful_constructed( + type_engine: &TypeEngine, factory: &ConstructorFactory, p: &Matrix, q: &PatStack, @@ -574,7 +578,7 @@ fn is_useful_constructed( ); // 3. Recursively compute *U(S(c, P), S(c, q))* - is_useful(factory, &s_c_p, &s_c_q, span) + is_useful(type_engine, factory, &s_c_p, &s_c_q, span) } /// Computes a witness report from *U(P, q)* when *q* is an or-pattern @@ -589,6 +593,7 @@ fn is_useful_constructed( /// 2. Compute the witnesses from *U(P, q')* /// 3. Aggregate the witnesses from every *U(P, q')* fn is_useful_or( + type_engine: &TypeEngine, factory: &ConstructorFactory, p: &Matrix, q: &PatStack, @@ -612,7 +617,7 @@ fn is_useful_or( // 2. Compute the witnesses from *U(P, q')* let wr = check!( - is_useful(factory, &p, &v, span), + is_useful(type_engine, factory, &p, &v, span), return err(warnings, errors), warnings, errors diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs index 29dfa790cb2..e0b00cb923f 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs @@ -8,8 +8,7 @@ use crate::{ }, namespace::Namespace, }, - type_system::unify, - CompileResult, Ident, TypeId, + CompileResult, Ident, TypeEngine, TypeId, }; use sway_types::span::Span; @@ -62,6 +61,7 @@ pub(crate) type MatcherResult = (MatchReqMap, MatchDeclMap); /// ] /// ``` pub(crate) fn matcher( + type_engine: &TypeEngine, exp: &ty::TyExpression, scrutinee: ty::TyScrutinee, namespace: &mut Namespace, @@ -75,7 +75,11 @@ pub(crate) fn matcher( } = scrutinee; // unify the type of the scrutinee with the type of the expression - append!(unify(type_id, exp.return_type, &span, ""), warnings, errors); + append!( + type_engine.unify(type_id, exp.return_type, &span, ""), + warnings, + errors + ); if !errors.is_empty() { return err(warnings, errors); @@ -88,11 +92,15 @@ pub(crate) fn matcher( ty::TyScrutineeVariant::Constant(name, _, type_id) => { match_constant(exp, name, type_id, span) } - ty::TyScrutineeVariant::StructScrutinee(_, fields) => match_struct(exp, fields, namespace), + ty::TyScrutineeVariant::StructScrutinee(_, fields) => { + match_struct(type_engine, exp, fields, namespace) + } ty::TyScrutineeVariant::EnumScrutinee { value, variant, .. } => { - match_enum(exp, variant, *value, span, namespace) + match_enum(type_engine, exp, variant, *value, span, namespace) + } + ty::TyScrutineeVariant::Tuple(elems) => { + match_tuple(type_engine, exp, elems, span, namespace) } - ty::TyScrutineeVariant::Tuple(elems) => match_tuple(exp, elems, span, namespace), } } @@ -144,6 +152,7 @@ fn match_constant( } fn match_struct( + type_engine: &TypeEngine, exp: &ty::TyExpression, fields: Vec, namespace: &mut Namespace, @@ -159,7 +168,7 @@ fn match_struct( } in fields.into_iter() { let subfield = check!( - instantiate_struct_field_access(exp.clone(), field.clone(), field_span), + instantiate_struct_field_access(type_engine, exp.clone(), field.clone(), field_span), return err(warnings, errors), warnings, errors @@ -172,7 +181,7 @@ fn match_struct( // or if the scrutinee has a more complex agenda Some(scrutinee) => { let (mut new_match_req_map, mut new_match_decl_map) = check!( - matcher(&subfield, scrutinee, namespace), + matcher(type_engine, &subfield, scrutinee, namespace), return err(warnings, errors), warnings, errors @@ -187,6 +196,7 @@ fn match_struct( } fn match_enum( + type_engine: &TypeEngine, exp: &ty::TyExpression, variant: ty::TyEnumVariant, scrutinee: ty::TyScrutinee, @@ -195,9 +205,10 @@ fn match_enum( ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; - let (mut match_req_map, unsafe_downcast) = instantiate_unsafe_downcast(exp, variant, span); + let (mut match_req_map, unsafe_downcast) = + instantiate_unsafe_downcast(type_engine, exp, variant, span); let (mut new_match_req_map, match_decl_map) = check!( - matcher(&unsafe_downcast, scrutinee, namespace), + matcher(type_engine, &unsafe_downcast, scrutinee, namespace), return err(warnings, errors), warnings, errors @@ -207,6 +218,7 @@ fn match_enum( } fn match_tuple( + type_engine: &TypeEngine, exp: &ty::TyExpression, elems: Vec, span: Span, @@ -218,13 +230,19 @@ fn match_tuple( let mut match_decl_map = vec![]; for (pos, elem) in elems.into_iter().enumerate() { let tuple_index_access = check!( - instantiate_tuple_index_access(exp.clone(), pos, span.clone(), span.clone()), + instantiate_tuple_index_access( + type_engine, + exp.clone(), + pos, + span.clone(), + span.clone() + ), return err(warnings, errors), warnings, errors ); let (mut new_match_req_map, mut new_match_decl_map) = check!( - matcher(&tuple_index_access, elem, namespace), + matcher(type_engine, &tuple_index_access, elem, namespace), return err(warnings, errors), warnings, errors diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs index a12f3bc0476..3815d2d11df 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs @@ -4,7 +4,6 @@ use crate::{ error::{err, ok}, language::{parsed::MatchBranch, ty}, semantic_analysis::*, - type_system::insert_type, types::DeterministicallyAborts, CompileResult, TypeInfo, }; @@ -26,6 +25,8 @@ impl ty::TyMatchBranch { span: branch_span, } = branch; + let type_engine = ctx.type_engine; + // type check the scrutinee let typed_scrutinee = check!( ty::TyScrutinee::type_check(ctx.by_ref(), scrutinee), @@ -36,7 +37,12 @@ impl ty::TyMatchBranch { // calculate the requirements map and the declarations map let (match_req_map, match_decl_map) = check!( - matcher(typed_value, typed_scrutinee.clone(), ctx.namespace), + matcher( + type_engine, + typed_value, + typed_scrutinee.clone(), + ctx.namespace + ), return err(warnings, errors), warnings, errors @@ -71,7 +77,7 @@ impl ty::TyMatchBranch { let typed_result = { let ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); check!( ty::TyExpression::type_check(ctx, result), return err(warnings, errors), diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs index 79a97ff69a0..452bb76b799 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs @@ -9,7 +9,6 @@ use crate::{ }, TypeCheckContext, }, - type_system::insert_type, CompileError, CompileResult, TypeInfo, }; @@ -58,6 +57,8 @@ impl ty::TyMatchExpression { let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + let ty::TyMatchExpression { branches, .. } = self; // create the typed if expression object that we will be building on to @@ -87,7 +88,7 @@ impl ty::TyMatchExpression { LazyOp::And, new_condition, inner_condition, - insert_type(TypeInfo::Boolean), + type_engine.insert_type(TypeInfo::Boolean), joined_span, ) } @@ -103,6 +104,7 @@ impl ty::TyMatchExpression { (None, Some(conditional)) => { check!( instantiate_if_expression( + ctx.type_engine, conditional, result.clone(), Some(result), // TODO: this is a really bad hack and we should not do this @@ -118,11 +120,12 @@ impl ty::TyMatchExpression { (Some(prev_if_exp), None) => { let conditional = ty::TyExpression { expression: ty::TyExpressionVariant::Literal(Literal::Boolean(true)), - return_type: insert_type(TypeInfo::Boolean), + return_type: type_engine.insert_type(TypeInfo::Boolean), span: result_span.clone(), }; check!( instantiate_if_expression( + ctx.type_engine, conditional, result, Some(prev_if_exp), @@ -138,6 +141,7 @@ impl ty::TyMatchExpression { (Some(prev_if_exp), Some(conditional)) => { check!( instantiate_if_expression( + ctx.type_engine, conditional, result, Some(prev_if_exp), diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs index bd7731ba254..a596bd0535f 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs @@ -5,7 +5,7 @@ use crate::{ error::{err, ok}, language::{parsed::*, ty, CallPath}, semantic_analysis::TypeCheckContext, - type_system::{insert_type, CreateTypeId, EnforceTypeArguments, TypeArgument}, + type_system::{CreateTypeId, EnforceTypeArguments, TypeArgument}, CompileError, CompileResult, TypeInfo, }; @@ -17,7 +17,7 @@ impl ty::TyScrutinee { Scrutinee::CatchAll { span } => { let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::CatchAll, - type_id: insert_type(TypeInfo::Unknown), + type_id: ctx.type_engine.insert_type(TypeInfo::Unknown), span, }; ok(typed_scrutinee, warnings, errors) @@ -25,7 +25,7 @@ impl ty::TyScrutinee { Scrutinee::Literal { value, span } => { let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::Literal(value.clone()), - type_id: insert_type(value.to_typeinfo()), + type_id: ctx.type_engine.insert_type(value.to_typeinfo()), span, }; ok(typed_scrutinee, warnings, errors) @@ -86,7 +86,7 @@ fn type_check_variable( // Variable isn't a constant, so so we turn it into a [ty::TyScrutinee::Variable]. _ => ty::TyScrutinee { variant: ty::TyScrutineeVariant::Variable(name), - type_id: insert_type(TypeInfo::Unknown), + type_id: ctx.type_engine.insert_type(TypeInfo::Unknown), span, }, }; @@ -186,7 +186,7 @@ fn type_check_struct( let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::StructScrutinee(struct_decl.name.clone(), typed_fields), - type_id: struct_decl.create_type_id(), + type_id: struct_decl.create_type_id(ctx.type_engine), span, }; @@ -240,7 +240,7 @@ fn type_check_enum( warnings, errors ); - let enum_type_id = enum_decl.create_type_id(); + let enum_type_id = enum_decl.create_type_id(ctx.type_engine); // check to see if the variant exists and grab it if it does let variant = check!( @@ -288,7 +288,7 @@ fn type_check_tuple( errors )); } - let type_id = insert_type(TypeInfo::Tuple( + let type_id = ctx.type_engine.insert_type(TypeInfo::Tuple( typed_elems .iter() .map(|x| TypeArgument { diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 661cf06ff9d..6525800f466 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -110,14 +110,17 @@ impl ty::TyExpression { } pub(crate) fn type_check(mut ctx: TypeCheckContext, expr: Expression) -> CompileResult { + let type_engine = ctx.type_engine; let expr_span = expr.span(); let span = expr_span.clone(); let res = match expr.kind { // We've already emitted an error for the `::Error` case. - ExpressionKind::Error(_) => ok(ty::TyExpression::error(span), vec![], vec![]), - ExpressionKind::Literal(lit) => Self::type_check_literal(lit, span), + ExpressionKind::Error(_) => { + ok(ty::TyExpression::error(span, type_engine), vec![], vec![]) + } + ExpressionKind::Literal(lit) => Self::type_check_literal(lit, span, type_engine), ExpressionKind::Variable(name) => { - Self::type_check_variable_expression(ctx.namespace, name, span) + Self::type_check_variable_expression(ctx.namespace, type_engine, name, span) } ExpressionKind::FunctionApplication(function_application_expression) => { let FunctionApplicationExpression { @@ -134,7 +137,7 @@ impl ty::TyExpression { ExpressionKind::LazyOperator(LazyOperatorExpression { op, lhs, rhs }) => { let ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Boolean)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Boolean)); Self::type_check_lazy_operator(ctx, op, *lhs, *rhs, span) } ExpressionKind::CodeBlock(contents) => { @@ -217,14 +220,14 @@ impl ty::TyExpression { ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index }) => { let ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)) .with_help_text(""); Self::type_check_array_index(ctx, *prefix, *index, span) } ExpressionKind::StorageAccess(StorageAccessExpression { field_names }) => { let ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)) .with_help_text(""); Self::type_check_storage_load(ctx, field_names, &span) } @@ -238,7 +241,7 @@ impl ty::TyExpression { ExpressionKind::Break => { let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Break, - return_type: insert_type(TypeInfo::Unknown), + return_type: type_engine.insert_type(TypeInfo::Unknown), span, }; ok(expr, vec![], vec![]) @@ -246,7 +249,7 @@ impl ty::TyExpression { ExpressionKind::Continue => { let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Continue, - return_type: insert_type(TypeInfo::Unknown), + return_type: type_engine.insert_type(TypeInfo::Unknown), span, }; ok(expr, vec![], vec![]) @@ -265,7 +268,7 @@ impl ty::TyExpression { // is the responsibility of the function declaration to type check // all return statements contained within it. .by_ref() - .with_type_annotation(insert_type(TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)) .with_help_text( "Returned value must match up with the function return type \ annotation.", @@ -275,13 +278,13 @@ impl ty::TyExpression { let expr_span = expr.span(); let expr = check!( ty::TyExpression::type_check(ctx, *expr), - ty::TyExpression::error(expr_span), + ty::TyExpression::error(expr_span, type_engine), warnings, errors, ); let typed_expr = ty::TyExpression { expression: ty::TyExpressionVariant::Return(Box::new(expr)), - return_type: insert_type(TypeInfo::Unknown), + return_type: type_engine.insert_type(TypeInfo::Unknown), // FIXME: This should be Yes? span, }; @@ -310,7 +313,7 @@ impl ty::TyExpression { EnforceTypeArguments::No, None ), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -319,10 +322,11 @@ impl ty::TyExpression { // an UnsignedInteger or a Numeric if let ty::TyExpressionVariant::Literal(lit) = typed_expression.clone().expression { if let Literal::Numeric(_) = lit { - match look_up_type_id(typed_expression.return_type) { + match type_engine.look_up_type_id(typed_expression.return_type) { TypeInfo::UnsignedInteger(_) | TypeInfo::Numeric => { typed_expression = check!( Self::resolve_numeric_literal( + ctx, lit, expr_span, typed_expression.return_type @@ -340,7 +344,11 @@ impl ty::TyExpression { ok(typed_expression, warnings, errors) } - fn type_check_literal(lit: Literal, span: Span) -> CompileResult { + fn type_check_literal( + lit: Literal, + span: Span, + type_engine: &TypeEngine, + ) -> CompileResult { let return_type = match &lit { Literal::String(s) => TypeInfo::Str(s.as_str().len() as u64), Literal::Numeric(_) => TypeInfo::Numeric, @@ -351,7 +359,7 @@ impl ty::TyExpression { Literal::Boolean(_) => TypeInfo::Boolean, Literal::B256(_) => TypeInfo::B256, }; - let id = crate::type_system::insert_type(return_type); + let id = type_engine.insert_type(return_type); let exp = ty::TyExpression { expression: ty::TyExpressionVariant::Literal(lit), return_type: id, @@ -362,11 +370,13 @@ impl ty::TyExpression { pub(crate) fn type_check_variable_expression( namespace: &Namespace, + type_engine: &TypeEngine, name: Ident, span: Span, ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; + let exp = match namespace.resolve_symbol(&name).value { Some(ty::TyDeclaration::VariableDeclaration(decl)) => { let ty::TyVariableDeclaration { @@ -416,7 +426,7 @@ impl ty::TyExpression { errors ); ty::TyExpression { - return_type: decl.create_type_id(), + return_type: decl.create_type_id(type_engine), expression: ty::TyExpressionVariant::AbiName(AbiName::Known(decl.name.into())), span, } @@ -426,13 +436,13 @@ impl ty::TyExpression { name: name.clone(), what_it_is: a.friendly_name(), }); - ty::TyExpression::error(name.span()) + ty::TyExpression::error(name.span(), type_engine) } None => { errors.push(CompileError::UnknownVariable { var_name: name.clone(), }); - ty::TyExpression::error(name.span()) + ty::TyExpression::error(name.span(), type_engine) } }; ok(exp, warnings, errors) @@ -475,17 +485,19 @@ impl ty::TyExpression { ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; + let mut ctx = ctx.with_help_text(""); + let type_engine = ctx.type_engine; let typed_lhs = check!( ty::TyExpression::type_check(ctx.by_ref(), lhs.clone()), - ty::TyExpression::error(lhs.span()), + ty::TyExpression::error(lhs.span(), type_engine), warnings, errors ); let typed_rhs = check!( ty::TyExpression::type_check(ctx.by_ref(), rhs.clone()), - ty::TyExpression::error(rhs.span()), + ty::TyExpression::error(rhs.span(), type_engine), warnings, errors ); @@ -502,11 +514,13 @@ impl ty::TyExpression { ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; + + let type_engine = ctx.type_engine; let (typed_block, block_return_type) = check!( ty::TyCodeBlock::type_check(ctx.by_ref(), contents), ( ty::TyCodeBlock { contents: vec![] }, - crate::type_system::insert_type(TypeInfo::Tuple(Vec::new())) + type_engine.insert_type(TypeInfo::Tuple(Vec::new())) ), warnings, errors @@ -538,14 +552,16 @@ impl ty::TyExpression { ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; + + let type_engine = ctx.type_engine; let condition = { let ctx = ctx .by_ref() .with_help_text("The condition of an if expression must be a boolean expression.") - .with_type_annotation(insert_type(TypeInfo::Boolean)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Boolean)); check!( ty::TyExpression::type_check(ctx, condition.clone()), - ty::TyExpression::error(condition.span()), + ty::TyExpression::error(condition.span(), type_engine), warnings, errors ) @@ -554,10 +570,10 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); check!( ty::TyExpression::type_check(ctx, then.clone()), - ty::TyExpression::error(then.span()), + ty::TyExpression::error(then.span(), type_engine), warnings, errors ) @@ -566,16 +582,17 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); check!( ty::TyExpression::type_check(ctx, expr.clone()), - ty::TyExpression::error(expr.span()), + ty::TyExpression::error(expr.span(), type_engine), warnings, errors ) }); let exp = check!( instantiate_if_expression( + type_engine, condition, then, r#else, @@ -599,15 +616,17 @@ impl ty::TyExpression { let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + // type check the value let typed_value = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); check!( ty::TyExpression::type_check(ctx, value.clone()), - ty::TyExpression::error(value.span()), + ty::TyExpression::error(value.span(), type_engine), warnings, errors ) @@ -616,7 +635,9 @@ impl ty::TyExpression { // check to make sure that the type of the value is something that can be matched upon check!( - look_up_type_id(type_id).expect_is_supported_in_match_expressions(&typed_value.span), + type_engine + .look_up_type_id(type_id) + .expect_is_supported_in_match_expressions(&typed_value.span), return err(warnings, errors), warnings, errors @@ -635,7 +656,7 @@ impl ty::TyExpression { // check to see if the match expression is exhaustive and if all match arms are reachable let (witness_report, arms_reachability) = check!( - check_match_expression_usefulness(type_id, typed_scrutinees, span.clone()), + check_match_expression_usefulness(type_engine, type_id, typed_scrutinees, span.clone()), return err(warnings, errors), warnings, errors @@ -676,6 +697,8 @@ impl ty::TyExpression { let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + // Various checks that we can catch early to check that the assembly is valid. For now, // this includes two checks: // 1. Check that no control flow opcodes are used. @@ -694,12 +717,12 @@ impl ty::TyExpression { .unwrap_or_else(|| asm.whole_block_span.clone()); let return_type = check!( ctx.resolve_type_with_self( - insert_type(asm.return_type.clone()), + type_engine.insert_type(asm.return_type.clone()), &asm_span, EnforceTypeArguments::No, None ), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors, ); @@ -716,10 +739,10 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); check!( ty::TyExpression::type_check(ctx, initializer.clone()), - ty::TyExpression::error(initializer.span()), + ty::TyExpression::error(initializer.span(), type_engine), warnings, errors ) @@ -751,6 +774,8 @@ impl ty::TyExpression { let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + let TypeBinding { inner: CallPath { prefixes, suffix, .. @@ -788,20 +813,20 @@ impl ty::TyExpression { // resolve the type of the struct decl let type_id = check!( ctx.resolve_type_with_self( - insert_type(type_info), + type_engine.insert_type(type_info), &inner_span, EnforceTypeArguments::No, Some(&type_info_prefix) ), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors ); // extract the struct name and fields from the type info - let type_info = look_up_type_id(type_id); + let type_info = type_engine.look_up_type_id(type_id); let (struct_name, struct_fields) = check!( - type_info.expect_struct(&span), + type_info.expect_struct(type_engine, &span), return err(warnings, errors), warnings, errors @@ -824,7 +849,7 @@ impl ty::TyExpression { name: def_field.name.clone(), value: ty::TyExpression { expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, - return_type: insert_type(TypeInfo::ErrorRecovery), + return_type: type_engine.insert_type(TypeInfo::ErrorRecovery), span: span.clone(), }, }); @@ -837,7 +862,7 @@ impl ty::TyExpression { .with_help_text( "Struct field's type must match up with the type specified in its declaration.", ) - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let typed_field = check!( ty::TyExpression::type_check(ctx, expr_field.value), continue, @@ -845,7 +870,7 @@ impl ty::TyExpression { errors ); append!( - unify_adt( + type_engine.unify_adt( typed_field.return_type, def_field.type_id, &typed_field.span, @@ -893,9 +918,11 @@ impl ty::TyExpression { ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; + + let type_engine = ctx.type_engine; let ctx = ctx .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let parent = check!( ty::TyExpression::type_check(ctx, prefix), return err(warnings, errors), @@ -903,7 +930,7 @@ impl ty::TyExpression { errors ); let exp = check!( - instantiate_struct_field_access(parent, field_to_access, span), + instantiate_struct_field_access(type_engine, parent, field_to_access, span), return err(warnings, errors), warnings, errors @@ -918,7 +945,9 @@ impl ty::TyExpression { ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; - let field_type_opt = match look_up_type_id(ctx.type_annotation()) { + + let type_engine = ctx.type_engine; + let field_type_opt = match type_engine.look_up_type_id(ctx.type_annotation()) { TypeInfo::Tuple(field_type_ids) if field_type_ids.len() == fields.len() => { Some(field_type_ids) } @@ -930,7 +959,14 @@ impl ty::TyExpression { let field_type = field_type_opt .as_ref() .map(|field_type_ids| field_type_ids[i].clone()) - .unwrap_or_default(); + .unwrap_or_else(|| { + let initial_type_id = type_engine.insert_type(TypeInfo::Unknown); + TypeArgument { + type_id: initial_type_id, + initial_type_id, + span: Span::dummy(), + } + }); let field_span = field.span(); let ctx = ctx .by_ref() @@ -938,7 +974,7 @@ impl ty::TyExpression { .with_type_annotation(field_type.type_id); let typed_field = check!( ty::TyExpression::type_check(ctx, field), - ty::TyExpression::error(field_span), + ty::TyExpression::error(field_span, type_engine), warnings, errors ); @@ -953,7 +989,9 @@ impl ty::TyExpression { expression: ty::TyExpressionVariant::Tuple { fields: typed_fields, }, - return_type: crate::type_system::insert_type(TypeInfo::Tuple(typed_field_types)), + return_type: ctx + .type_engine + .insert_type(TypeInfo::Tuple(typed_field_types)), span, }; ok(exp, warnings, errors) @@ -984,7 +1022,7 @@ impl ty::TyExpression { // Do all namespace checking here! let (storage_access, return_type) = check!( ctx.namespace - .apply_storage_load(checkee, &storage_fields, span), + .apply_storage_load(ctx.type_engine, checkee, &storage_fields, span), return err(warnings, errors), warnings, errors @@ -1009,9 +1047,11 @@ impl ty::TyExpression { ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; + + let type_engine = ctx.type_engine; let ctx = ctx .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let parent = check!( ty::TyExpression::type_check(ctx, prefix), return err(warnings, errors), @@ -1019,7 +1059,7 @@ impl ty::TyExpression { errors ); let exp = check!( - instantiate_tuple_index_access(parent, index, index_span, span), + instantiate_tuple_index_access(type_engine, parent, index, index_span, span), return err(warnings, errors), warnings, errors @@ -1266,6 +1306,8 @@ impl ty::TyExpression { let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + // TODO use lib-std's Address type instead of b256 // type check the address and make sure it is let err_span = address.span(); @@ -1273,10 +1315,10 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("An address that is being ABI cast must be of type b256") - .with_type_annotation(insert_type(TypeInfo::B256)); + .with_type_annotation(type_engine.insert_type(TypeInfo::B256)); check!( ty::TyExpression::type_check(ctx, address), - ty::TyExpression::error(err_span), + ty::TyExpression::error(err_span, type_engine), warnings, errors ) @@ -1306,7 +1348,7 @@ impl ty::TyExpression { } ty::TyDeclaration::VariableDeclaration(ref decl) => { let ty::TyVariableDeclaration { body: expr, .. } = &**decl; - let ret_ty = look_up_type_id(expr.return_type); + let ret_ty = type_engine.look_up_type_id(expr.return_type); let abi_name = match ret_ty { TypeInfo::ContractCaller { abi_name, .. } => abi_name, _ => { @@ -1336,7 +1378,7 @@ impl ty::TyExpression { AbiName::Deferred => { return ok( ty::TyExpression { - return_type: insert_type(TypeInfo::ContractCaller { + return_type: type_engine.insert_type(TypeInfo::ContractCaller { abi_name: AbiName::Deferred, address: None, }), @@ -1358,7 +1400,7 @@ impl ty::TyExpression { } }; - let return_type = insert_type(TypeInfo::ContractCaller { + let return_type = type_engine.insert_type(TypeInfo::ContractCaller { abi_name: AbiName::Known(abi_name.clone()), address: Some(Box::new(address_expr.clone())), }); @@ -1388,7 +1430,8 @@ impl ty::TyExpression { return_type, &abi_methods, &span, - false + false, + type_engine, ), return err(warnings, errors), warnings, @@ -1412,14 +1455,20 @@ impl ty::TyExpression { contents: Vec, span: Span, ) -> CompileResult { + let type_engine = ctx.type_engine; + if contents.is_empty() { - let unknown_type = insert_type(TypeInfo::Unknown); + let unknown_type = type_engine.insert_type(TypeInfo::Unknown); return ok( ty::TyExpression { expression: ty::TyExpressionVariant::Array { contents: Vec::new(), }, - return_type: insert_type(TypeInfo::Array(unknown_type, 0, unknown_type)), + return_type: type_engine.insert_type(TypeInfo::Array( + unknown_type, + 0, + unknown_type, + )), span, }, Vec::new(), @@ -1436,10 +1485,10 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); check!( Self::type_check(ctx, expr), - ty::TyExpression::error(span), + ty::TyExpression::error(span, type_engine), warnings, errors ) @@ -1469,7 +1518,11 @@ impl ty::TyExpression { expression: ty::TyExpressionVariant::Array { contents: typed_contents, }, - return_type: insert_type(TypeInfo::Array(elem_type, array_count, elem_type)), // Maybe? + return_type: type_engine.insert_type(TypeInfo::Array( + elem_type, + array_count, + elem_type, + )), // Maybe? span, }, warnings, @@ -1486,11 +1539,13 @@ impl ty::TyExpression { let mut warnings = Vec::new(); let mut errors = Vec::new(); + let type_engine = ctx.type_engine; + let prefix_te = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); check!( ty::TyExpression::type_check(ctx, prefix.clone()), return err(warnings, errors), @@ -1500,11 +1555,13 @@ impl ty::TyExpression { }; // If the return type is a static array then create a `ty::TyExpressionVariant::ArrayIndex`. - if let TypeInfo::Array(elem_type_id, _, _) = look_up_type_id(prefix_te.return_type) { + if let TypeInfo::Array(elem_type_id, _, _) = + type_engine.look_up_type_id(prefix_te.return_type) + { let type_info_u64 = TypeInfo::UnsignedInteger(IntegerBits::SixtyFour); let ctx = ctx .with_help_text("") - .with_type_annotation(insert_type(type_info_u64)); + .with_type_annotation(type_engine.insert_type(type_info_u64)); let index_te = check!( ty::TyExpression::type_check(ctx, index), return err(warnings, errors), @@ -1574,10 +1631,12 @@ impl ty::TyExpression { ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; + + let type_engine = ctx.type_engine; let typed_condition = { let ctx = ctx .by_ref() - .with_type_annotation(insert_type(TypeInfo::Boolean)) + .with_type_annotation(type_engine.insert_type(TypeInfo::Boolean)) .with_help_text("A while loop's loop condition must be a boolean expression."); check!( ty::TyExpression::type_check(ctx, condition), @@ -1587,7 +1646,7 @@ impl ty::TyExpression { ) }; - let unit_ty = insert_type(TypeInfo::Tuple(Vec::new())); + let unit_ty = type_engine.insert_type(TypeInfo::Tuple(Vec::new())); let ctx = ctx.with_type_annotation(unit_ty).with_help_text( "A while loop's loop body cannot implicitly return a value. Try \ assigning it to a mutable variable declared outside of the loop \ @@ -1618,8 +1677,10 @@ impl ty::TyExpression { ) -> CompileResult { let mut errors = vec![]; let mut warnings = vec![]; + + let type_engine = ctx.type_engine; let ctx = ctx - .with_type_annotation(insert_type(TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)) .with_help_text(""); // ensure that the lhs is a variable expression or struct field access match lhs { @@ -1675,7 +1736,8 @@ impl ty::TyExpression { }; let names_vec = names_vec.into_iter().rev().collect::>(); let (ty_of_field, _ty_of_parent) = check!( - ctx.namespace.find_subfield_type(&base_name, &names_vec), + ctx.namespace + .find_subfield_type(type_engine, &base_name, &names_vec), return err(warnings, errors), warnings, errors @@ -1685,7 +1747,7 @@ impl ty::TyExpression { let rhs_span = rhs.span(); let rhs = check!( ty::TyExpression::type_check(ctx, rhs), - ty::TyExpression::error(rhs_span), + ty::TyExpression::error(rhs_span, type_engine), warnings, errors ); @@ -1700,7 +1762,7 @@ impl ty::TyExpression { rhs, }, )), - return_type: crate::type_system::insert_type(TypeInfo::Tuple(Vec::new())), + return_type: type_engine.insert_type(TypeInfo::Tuple(Vec::new())), span, }, warnings, @@ -1709,7 +1771,7 @@ impl ty::TyExpression { } ReassignmentTarget::StorageField(fields) => { let ctx = ctx - .with_type_annotation(insert_type(TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)) .with_help_text(""); let reassignment = check!( reassign_storage_subfield(ctx, fields, rhs, span.clone()), @@ -1722,7 +1784,7 @@ impl ty::TyExpression { expression: ty::TyExpressionVariant::StorageReassignment(Box::new( reassignment, )), - return_type: crate::type_system::insert_type(TypeInfo::Tuple(Vec::new())), + return_type: type_engine.insert_type(TypeInfo::Tuple(Vec::new())), span, }, warnings, @@ -1733,19 +1795,23 @@ impl ty::TyExpression { } fn resolve_numeric_literal( + ctx: TypeCheckContext, lit: Literal, span: Span, new_type: TypeId, ) -> CompileResult { let mut errors = vec![]; + let type_engine = ctx.type_engine; + // Parse and resolve a Numeric(span) based on new_type. let (val, new_integer_type) = match lit { - Literal::Numeric(num) => match look_up_type_id(new_type) { + Literal::Numeric(num) => match type_engine.look_up_type_id(new_type) { TypeInfo::UnsignedInteger(n) => match n { IntegerBits::Eight => ( num.to_string().parse().map(Literal::U8).map_err(|e| { Literal::handle_parse_int_error( + type_engine, e, TypeInfo::UnsignedInteger(IntegerBits::Eight), span.clone(), @@ -1756,6 +1822,7 @@ impl ty::TyExpression { IntegerBits::Sixteen => ( num.to_string().parse().map(Literal::U16).map_err(|e| { Literal::handle_parse_int_error( + type_engine, e, TypeInfo::UnsignedInteger(IntegerBits::Sixteen), span.clone(), @@ -1766,6 +1833,7 @@ impl ty::TyExpression { IntegerBits::ThirtyTwo => ( num.to_string().parse().map(Literal::U32).map_err(|e| { Literal::handle_parse_int_error( + type_engine, e, TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo), span.clone(), @@ -1776,6 +1844,7 @@ impl ty::TyExpression { IntegerBits::SixtyFour => ( num.to_string().parse().map(Literal::U64).map_err(|e| { Literal::handle_parse_int_error( + type_engine, e, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), span.clone(), @@ -1787,12 +1856,13 @@ impl ty::TyExpression { TypeInfo::Numeric => ( num.to_string().parse().map(Literal::U64).map_err(|e| { Literal::handle_parse_int_error( + type_engine, e, TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), span.clone(), ) }), - insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + type_engine.insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), ), _ => unreachable!("Unexpected type for integer literals"), }, @@ -1810,7 +1880,7 @@ impl ty::TyExpression { } Err(e) => { errors.push(e); - let exp = ty::TyExpression::error(span); + let exp = ty::TyExpression::error(span, type_engine); ok(exp, vec![], errors) } } @@ -1822,19 +1892,26 @@ mod tests { use super::*; use sway_error::type_error::TypeError; - fn do_type_check(expr: Expression, type_annotation: TypeId) -> CompileResult { + fn do_type_check( + type_engine: &TypeEngine, + expr: Expression, + type_annotation: TypeId, + ) -> CompileResult { let mut namespace = Namespace::init_root(namespace::Module::default()); - let ctx = TypeCheckContext::from_root(&mut namespace).with_type_annotation(type_annotation); + let ctx = TypeCheckContext::from_root(&mut namespace, type_engine) + .with_type_annotation(type_annotation); ty::TyExpression::type_check(ctx, expr) } fn do_type_check_for_boolx2(expr: Expression) -> CompileResult { + let type_engine = TypeEngine::default(); do_type_check( + &type_engine, expr, - insert_type(TypeInfo::Array( - insert_type(TypeInfo::Boolean), + type_engine.insert_type(TypeInfo::Array( + type_engine.insert_type(TypeInfo::Boolean), 2, - insert_type(TypeInfo::Boolean), + type_engine.insert_type(TypeInfo::Boolean), )), ) } @@ -1941,12 +2018,14 @@ mod tests { span: Span::dummy(), }; + let type_engine = TypeEngine::default(); let comp_res = do_type_check( + &type_engine, expr, - insert_type(TypeInfo::Array( - insert_type(TypeInfo::Boolean), + type_engine.insert_type(TypeInfo::Array( + type_engine.insert_type(TypeInfo::Boolean), 0, - insert_type(TypeInfo::Boolean), + type_engine.insert_type(TypeInfo::Boolean), )), ); assert!(comp_res.warnings.is_empty() && comp_res.errors.is_empty()); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs index 1d7617a2c17..d0c066a6e1d 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs @@ -21,6 +21,8 @@ pub(crate) fn instantiate_enum( let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + let enum_variant = check!( enum_decl .expect_variant_from_name(&enum_variant_name) @@ -33,10 +35,10 @@ pub(crate) fn instantiate_enum( // If there is an instantiator, it must match up with the type. If there is not an // instantiator, then the type of the enum is necessarily the unit type. - match (&args[..], look_up_type_id(enum_variant.type_id)) { + match (&args[..], type_engine.look_up_type_id(enum_variant.type_id)) { ([], ty) if ty.is_unit() => ok( ty::TyExpression { - return_type: enum_decl.create_type_id(), + return_type: enum_decl.create_type_id(ctx.type_engine), expression: ty::TyExpressionVariant::EnumInstantiation { tag: enum_variant.tag, contents: None, @@ -53,7 +55,7 @@ pub(crate) fn instantiate_enum( ([single_expr], _) => { let ctx = ctx .with_help_text("Enum instantiator must match its declared variant type.") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let typed_expr = check!( ty::TyExpression::type_check(ctx, single_expr.clone()), return err(warnings, errors), @@ -61,7 +63,7 @@ pub(crate) fn instantiate_enum( errors ); append!( - unify_adt( + type_engine.unify_adt( typed_expr.return_type, enum_variant.type_id, &typed_expr.span, @@ -76,7 +78,7 @@ pub(crate) fn instantiate_enum( ok( ty::TyExpression { - return_type: enum_decl.create_type_id(), + return_type: enum_decl.create_type_id(type_engine), expression: ty::TyExpressionVariant::EnumInstantiation { tag: enum_variant.tag, contents: Some(Box::new(typed_expr)), @@ -106,7 +108,7 @@ pub(crate) fn instantiate_enum( (_too_many_expressions, ty) => { errors.push(CompileError::MoreThanOneEnumInstantiator { span: enum_variant_name.span(), - ty: ty.to_string(), + ty: type_engine.help_out(ty).to_string(), }); err(warnings, errors) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs index 7bba53675ba..0621ea7a82b 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs @@ -18,6 +18,8 @@ pub(crate) fn instantiate_function_application( let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + // 'purity' is that of the callee, 'opts.purity' of the caller. if !ctx.purity().can_call(function_decl.purity) { errors.push(CompileError::StorageAccessMismatch { @@ -47,15 +49,15 @@ pub(crate) fn instantiate_function_application( not match the declared type of the parameter in the function \ declaration.", ) - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); let exp = check!( ty::TyExpression::type_check(ctx, arg.clone()), - ty::TyExpression::error(arg.span()), + ty::TyExpression::error(arg.span(), type_engine), warnings, errors ); append!( - unify_right( + type_engine.unify_right( exp.return_type, param.type_id, &exp.span, @@ -91,7 +93,7 @@ pub(crate) fn instantiate_function_application( warnings, errors ); - function_decl.replace_decls(&decl_mapping); + function_decl.replace_decls(&decl_mapping, type_engine); let return_type = function_decl.return_type; let span = function_decl.span.clone(); let new_decl_id = de_insert_function(function_decl); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs index cca5e80a136..23403dcedad 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs @@ -4,6 +4,7 @@ use sway_types::Span; use crate::{error::*, language::ty, type_system::*, types::DeterministicallyAborts}; pub(crate) fn instantiate_if_expression( + type_engine: &TypeEngine, condition: ty::TyExpression, then: ty::TyExpression, r#else: Option, @@ -21,10 +22,10 @@ pub(crate) fn instantiate_if_expression( let ty_to_check = if r#else.is_some() { type_annotation } else { - insert_type(TypeInfo::Tuple(vec![])) + type_engine.insert_type(TypeInfo::Tuple(vec![])) }; append!( - unify_with_self( + type_engine.unify_with_self( then.return_type, ty_to_check, self_type, @@ -46,7 +47,7 @@ pub(crate) fn instantiate_if_expression( if !else_deterministically_aborts { // if this does not deterministically_abort, check the block return type append!( - unify_with_self( + type_engine.unify_with_self( r#else.return_type, ty_to_check, self_type, @@ -63,10 +64,10 @@ pub(crate) fn instantiate_if_expression( let r#else_ret_ty = r#else .as_ref() .map(|x| x.return_type) - .unwrap_or_else(|| insert_type(TypeInfo::Tuple(Vec::new()))); + .unwrap_or_else(|| type_engine.insert_type(TypeInfo::Tuple(Vec::new()))); // if there is a type annotation, then the else branch must exist if !else_deterministically_aborts && !then_deterministically_aborts { - let (mut new_warnings, mut new_errors) = unify_with_self( + let (mut new_warnings, mut new_errors) = type_engine.unify_with_self( then.return_type, r#else_ret_ty, self_type, @@ -75,10 +76,10 @@ pub(crate) fn instantiate_if_expression( ); warnings.append(&mut new_warnings); if new_errors.is_empty() { - if !look_up_type_id(r#else_ret_ty).is_unit() && r#else.is_none() { + if !type_engine.look_up_type_id(r#else_ret_ty).is_unit() && r#else.is_none() { errors.push(CompileError::NoElseBranch { span: span.clone(), - r#type: look_up_type_id(type_annotation).to_string(), + r#type: type_engine.help_out(type_annotation).to_string(), }); } } else { diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index 0d8e6695af0..ac1e49e471f 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -23,16 +23,18 @@ pub(crate) fn type_check_method_application( let mut warnings = vec![]; let mut errors = vec![]; + let type_engine = ctx.type_engine; + // type check the function arguments let mut args_buf = VecDeque::new(); for arg in &arguments { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(insert_type(TypeInfo::Unknown)); + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)); args_buf.push_back(check!( ty::TyExpression::type_check(ctx, arg.clone()), - ty::TyExpression::error(span.clone()), + ty::TyExpression::error(span.clone(), type_engine), warnings, errors )); @@ -106,13 +108,15 @@ pub(crate) fn type_check_method_application( constants::CONTRACT_CALL_GAS_PARAMETER_NAME | constants::CONTRACT_CALL_COINS_PARAMETER_NAME | constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME => { - let type_annotation = if param.name.span().as_str() - != constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME - { - insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)) - } else { - insert_type(TypeInfo::B256) - }; + let type_annotation = ctx.type_engine.insert_type( + if param.name.span().as_str() + != constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME + { + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) + } else { + TypeInfo::B256 + }, + ); let ctx = ctx .by_ref() .with_help_text("") @@ -121,7 +125,7 @@ pub(crate) fn type_check_method_application( param.name.to_string(), check!( ty::TyExpression::type_check(ctx, param.value), - ty::TyExpression::error(span.clone()), + ty::TyExpression::error(span.clone(), type_engine), warnings, errors ), @@ -258,16 +262,17 @@ pub(crate) fn type_check_method_application( // build the function selector let selector = if method.is_contract_call { let contract_caller = args_buf.pop_front(); - let contract_address = match contract_caller.map(|x| look_up_type_id(x.return_type)) { - Some(TypeInfo::ContractCaller { address, .. }) => address, - _ => { - errors.push(CompileError::Internal( - "Attempted to find contract address of non-contract-call.", - span.clone(), - )); - None - } - }; + let contract_address = + match contract_caller.map(|x| type_engine.look_up_type_id(x.return_type)) { + Some(TypeInfo::ContractCaller { address, .. }) => address, + _ => { + errors.push(CompileError::Internal( + "Attempted to find contract address of non-contract-call.", + span.clone(), + )); + None + } + }; let contract_address = if let Some(addr) = contract_address { addr } else { @@ -276,7 +281,12 @@ pub(crate) fn type_check_method_application( }); return err(warnings, errors); }; - let func_selector = check!(method.to_fn_selector_value(), [0; 4], warnings, errors); + let func_selector = check!( + method.to_fn_selector_value(type_engine), + [0; 4], + warnings, + errors + ); Some(ty::ContractCallParams { func_selector, contract_address, @@ -295,7 +305,7 @@ pub(crate) fn type_check_method_application( // unify the types of the arguments with the types of the parameters from the function declaration for (arg, param) in args_buf.iter().zip(method.parameters.iter()) { - let (mut new_warnings, new_errors) = unify_right_with_self( + let (mut new_warnings, new_errors) = type_engine.unify_right_with_self( arg.return_type, param.type_id, ctx.self_type(), @@ -306,8 +316,8 @@ pub(crate) fn type_check_method_application( if !new_errors.is_empty() { errors.push(CompileError::ArgumentParameterTypeMismatch { span: arg.span.clone(), - provided: arg.return_type.to_string(), - should_be: param.type_id.to_string(), + provided: type_engine.help_out(arg.return_type).to_string(), + should_be: type_engine.help_out(param.type_id).to_string(), }); } } @@ -353,7 +363,7 @@ pub(crate) fn resolve_method_name( // type check the call path let type_id = check!( call_path_binding.type_check_with_type_info(&mut ctx), - insert_type(TypeInfo::ErrorRecovery), + ctx.type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors ); @@ -376,7 +386,8 @@ pub(crate) fn resolve_method_name( &type_info_prefix, method_name, ctx.self_type(), - &arguments + &arguments, + ctx.type_engine, ), return err(warnings, errors), warnings, @@ -391,7 +402,7 @@ pub(crate) fn resolve_method_name( let type_id = arguments .get(0) .map(|x| x.return_type) - .unwrap_or_else(|| insert_type(TypeInfo::Unknown)); + .unwrap_or_else(|| ctx.type_engine.insert_type(TypeInfo::Unknown)); // find the method check!( @@ -400,7 +411,8 @@ pub(crate) fn resolve_method_name( &module_path, &call_path.suffix, ctx.self_type(), - &arguments + &arguments, + ctx.type_engine, ), return err(warnings, errors), warnings, @@ -415,7 +427,7 @@ pub(crate) fn resolve_method_name( let type_id = arguments .get(0) .map(|x| x.return_type) - .unwrap_or_else(|| insert_type(TypeInfo::Unknown)); + .unwrap_or_else(|| ctx.type_engine.insert_type(TypeInfo::Unknown)); // find the method check!( @@ -424,7 +436,8 @@ pub(crate) fn resolve_method_name( &module_path, method_name, ctx.self_type(), - &arguments + &arguments, + ctx.type_engine, ), return err(warnings, errors), warnings, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_field_access.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_field_access.rs index 424994b276a..75e9a7db5b0 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_field_access.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_field_access.rs @@ -3,11 +3,11 @@ use sway_types::{Ident, Span, Spanned}; use crate::{ error::{err, ok}, language::ty, - type_system::look_up_type_id, - CompileResult, + CompileResult, TypeEngine, }; pub(crate) fn instantiate_struct_field_access( + type_engine: &TypeEngine, parent: ty::TyExpression, field_to_access: Ident, span: Span, @@ -16,7 +16,9 @@ pub(crate) fn instantiate_struct_field_access( let mut errors = vec![]; let field_instantiation_span = field_to_access.span(); let field = check!( - look_up_type_id(parent.return_type).apply_subfields(&[field_to_access], &parent.span), + type_engine + .look_up_type_id(parent.return_type) + .apply_subfields(type_engine, &[field_to_access], &parent.span), return err(warnings, errors), warnings, errors diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/tuple_index_access.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/tuple_index_access.rs index fa8f8cf2ace..858ff20585d 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/tuple_index_access.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/tuple_index_access.rs @@ -3,11 +3,11 @@ use sway_types::Span; use crate::{ error::{err, ok}, language::ty, - type_system::look_up_type_id, - CompileError, CompileResult, + CompileError, CompileResult, TypeEngine, }; pub(crate) fn instantiate_tuple_index_access( + type_engine: &TypeEngine, parent: ty::TyExpression, index: usize, index_span: Span, @@ -16,9 +16,9 @@ pub(crate) fn instantiate_tuple_index_access( let mut warnings = vec![]; let mut errors = vec![]; let mut tuple_type_arg_to_access = None; - let type_info = look_up_type_id(parent.return_type); + let type_info = type_engine.look_up_type_id(parent.return_type); let type_args = check!( - type_info.expect_tuple(parent.span.as_str(), &parent.span), + type_info.expect_tuple(type_engine, parent.span.as_str(), &parent.span), return err(warnings, errors), warnings, errors diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/unsafe_downcast.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/unsafe_downcast.rs index c442fc2ff92..97393441112 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/unsafe_downcast.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/unsafe_downcast.rs @@ -3,11 +3,11 @@ use sway_types::{integer_bits::IntegerBits, Span}; use crate::{ language::{ty, Literal}, semantic_analysis::ast_node::expression::match_expression::MatchReqMap, - type_system::insert_type, - TypeInfo, + TypeEngine, TypeInfo, }; // currently the unsafe downcast expr is only used for enums, so this method is specialized for enums pub(crate) fn instantiate_unsafe_downcast( + type_engine: &TypeEngine, exp: &ty::TyExpression, variant: ty::TyEnumVariant, span: Span, @@ -17,12 +17,12 @@ pub(crate) fn instantiate_unsafe_downcast( expression: ty::TyExpressionVariant::EnumTag { exp: Box::new(exp.clone()), }, - return_type: insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + return_type: type_engine.insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), span: exp.span.clone(), }, ty::TyExpression { expression: ty::TyExpressionVariant::Literal(Literal::U64(variant.tag as u64)), - return_type: insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), + return_type: type_engine.insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)), span: exp.span.clone(), }, )]; diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 4819f178f47..cc3dec3d018 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -24,6 +24,7 @@ impl ty::TyAstNode { let mut warnings = Vec::new(); let mut errors = Vec::new(); + let type_engine = ctx.type_engine; let node = ty::TyAstNode { content: match node.content.clone() { AstNodeContent::UseStatement(a) => { @@ -33,9 +34,13 @@ impl ty::TyAstNode { ctx.namespace.find_module_path(&a.call_path) }; let mut res = match a.import_type { - ImportType::Star => ctx.namespace.star_import(&path), - ImportType::SelfImport => ctx.namespace.self_import(&path, a.alias), - ImportType::Item(s) => ctx.namespace.item_import(&path, &s, a.alias), + ImportType::Star => ctx.namespace.star_import(&path, type_engine), + ImportType::SelfImport => { + ctx.namespace.self_import(ctx.type_engine, &path, a.alias) + } + ImportType::Item(s) => { + ctx.namespace.item_import(type_engine, &path, &s, a.alias) + } }; warnings.append(&mut res.warnings); errors.append(&mut res.errors); @@ -50,11 +55,11 @@ impl ty::TyAstNode { )), AstNodeContent::Expression(expr) => { let ctx = ctx - .with_type_annotation(insert_type(TypeInfo::Unknown)) + .with_type_annotation(type_engine.insert_type(TypeInfo::Unknown)) .with_help_text(""); let inner = check!( ty::TyExpression::type_check(ctx, expr.clone()), - ty::TyExpression::error(expr.span()), + ty::TyExpression::error(expr.span(), type_engine), warnings, errors ); @@ -65,7 +70,7 @@ impl ty::TyAstNode { ctx.with_help_text("Implicit return must match up with block's type."); let typed_expr = check!( ty::TyExpression::type_check(ctx, expr.clone()), - ty::TyExpression::error(expr.span()), + ty::TyExpression::error(expr.span(), type_engine), warnings, errors ); @@ -81,10 +86,12 @@ impl ty::TyAstNode { } = node { let warning = Warning::UnusedReturnValue { - r#type: node.type_info().to_string(), + r#type: type_engine + .help_out(node.type_info(type_engine)) + .to_string(), }; assert_or_warn!( - node.type_info().can_safely_ignore(), + node.type_info(type_engine).can_safely_ignore(type_engine), warnings, node.span.clone(), warning @@ -103,6 +110,8 @@ pub(crate) fn reassign_storage_subfield( ) -> CompileResult { let mut errors = vec![]; let mut warnings = vec![]; + + let type_engine = ctx.type_engine; if !ctx.namespace.has_storage_declared() { errors.push(CompileError::NoDeclaredStorage { span }); @@ -144,12 +153,10 @@ pub(crate) fn reassign_storage_subfield( span: first_field.span(), }); - fn update_available_struct_fields(id: TypeId) -> Vec { - match look_up_type_id(id) { - TypeInfo::Struct { fields, .. } => fields, - _ => vec![], - } - } + let update_available_struct_fields = |id: TypeId| match type_engine.look_up_type_id(id) { + TypeInfo::Struct { fields, .. } => fields, + _ => vec![], + }; let mut curr_type = *initial_field_type; // if the previously iterated type was a struct, put its fields here so we know that, @@ -189,7 +196,7 @@ pub(crate) fn reassign_storage_subfield( let ctx = ctx.with_type_annotation(curr_type).with_help_text(""); let rhs = check!( ty::TyExpression::type_check(ctx, rhs), - ty::TyExpression::error(span), + ty::TyExpression::error(span, type_engine), warnings, errors ); diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index 62d6c8b3652..a47397612ed 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -24,8 +24,10 @@ impl ty::TyModule { } // TODO: Ordering should be solved across all modules prior to the beginning of type-check. - let ordered_nodes_res = - node_dependencies::order_ast_nodes_by_dependency(tree.root_nodes.clone()); + let ordered_nodes_res = node_dependencies::order_ast_nodes_by_dependency( + ctx.type_engine, + tree.root_nodes.clone(), + ); let typed_nodes_res = ordered_nodes_res .flat_map(|ordered_nodes| Self::type_check_nodes(ctx.by_ref(), ordered_nodes)); diff --git a/sway-core/src/semantic_analysis/namespace/items.rs b/sway-core/src/semantic_analysis/namespace/items.rs index 7767029f450..3df82a7ba79 100644 --- a/sway-core/src/semantic_analysis/namespace/items.rs +++ b/sway-core/src/semantic_analysis/namespace/items.rs @@ -28,7 +28,7 @@ pub(super) type UseSynonyms = im::HashMap, GlobImport)>; pub(super) type UseAliases = im::HashMap; /// The set of items that exist within some lexical scope via declaration or importing. -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default)] pub struct Items { /// An ordered map from `Ident`s to their associated typed declarations. pub(crate) symbols: SymbolMap, @@ -55,6 +55,7 @@ impl Items { pub fn apply_storage_load( &self, + type_engine: &TypeEngine, fields: Vec, storage_fields: &[ty::TyStorageField], access_span: &Span, @@ -69,7 +70,7 @@ impl Items { warnings, errors ); - storage.apply_storage_load(fields, storage_fields) + storage.apply_storage_load(type_engine, fields, storage_fields) } None => { errors.push(CompileError::NoDeclaredStorage { @@ -133,6 +134,7 @@ impl Items { .ok_or_else(|| CompileError::SymbolNotFound { name: name.clone() }) } + #[allow(clippy::too_many_arguments)] pub(crate) fn insert_trait_implementation( &mut self, trait_name: CallPath, @@ -141,6 +143,7 @@ impl Items { methods: &[DeclarationId], impl_span: &Span, is_impl_self: bool, + type_engine: &TypeEngine, ) -> CompileResult<()> { let new_prefixes = if trait_name.prefixes.is_empty() { self.use_synonyms @@ -163,24 +166,39 @@ impl Items { methods, impl_span, is_impl_self, + type_engine, ) } - pub(crate) fn insert_trait_implementation_for_type(&mut self, type_id: TypeId) { - self.implemented_traits.insert_for_type(type_id); + pub(crate) fn insert_trait_implementation_for_type( + &mut self, + type_engine: &TypeEngine, + type_id: TypeId, + ) { + self.implemented_traits + .insert_for_type(type_engine, type_id); } - pub(crate) fn get_methods_for_type(&self, type_id: TypeId) -> Vec { - self.implemented_traits.get_methods_for_type(type_id) + pub(crate) fn get_methods_for_type( + &self, + type_engine: &TypeEngine, + type_id: TypeId, + ) -> Vec { + self.implemented_traits + .get_methods_for_type(type_engine, type_id) } pub(crate) fn get_methods_for_type_and_trait_name( &self, + type_engine: &TypeEngine, type_id: TypeId, trait_name: &CallPath, ) -> Vec { - self.implemented_traits - .get_methods_for_type_and_trait_name(type_id, trait_name) + self.implemented_traits.get_methods_for_type_and_trait_name( + type_engine, + type_id, + trait_name, + ) } pub(crate) fn has_storage_declared(&self) -> bool { @@ -216,6 +234,7 @@ impl Items { /// the second is the [ResolvedType] of its parent, for control-flow analysis. pub(crate) fn find_subfield_type( &self, + type_engine: &TypeEngine, base_name: &Ident, projections: &[ty::ProjectionKind], ) -> CompileResult<(TypeId, TypeId)> { @@ -231,7 +250,7 @@ impl Items { } }; let mut symbol = check!( - symbol.return_type(&base_name.span()), + symbol.return_type(&base_name.span(), type_engine), return err(warnings, errors), warnings, errors @@ -241,7 +260,7 @@ impl Items { let mut full_name_for_error = base_name.to_string(); let mut full_span_for_error = base_name.span(); for projection in projections { - let resolved_type = match to_typeinfo(symbol, &symbol_span) { + let resolved_type = match type_engine.to_typeinfo(symbol, &symbol_span) { Ok(resolved_type) => resolved_type, Err(error) => { errors.push(CompileError::TypeError(error)); @@ -322,7 +341,7 @@ impl Items { (actually, ty::ProjectionKind::StructField { .. }) => { errors.push(CompileError::FieldAccessOnNonStruct { span: full_span_for_error, - actually: actually.to_string(), + actually: type_engine.help_out(actually).to_string(), }); return err(warnings, errors); } @@ -330,7 +349,7 @@ impl Items { errors.push(CompileError::NotATuple { name: full_name_for_error, span: full_span_for_error, - actually: actually.to_string(), + actually: type_engine.help_out(actually).to_string(), }); return err(warnings, errors); } diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 87b63957698..0b9f271642d 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -3,7 +3,7 @@ use crate::{ language::{parsed::*, ty, Visibility}, semantic_analysis::*, transform::to_parsed_lang, - Ident, Namespace, + Ident, Namespace, TypeEngine, }; use super::{ @@ -28,7 +28,7 @@ use sway_types::{span::Span, ConfigTimeConstant, Spanned}; /// /// A `Module` contains a set of all items that exist within the lexical scope via declaration or /// importing, along with a map of each of its submodules. -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default)] pub struct Module { /// Submodules of the current module represented as an ordered map from each submodule's name /// to the associated `Module`. @@ -44,10 +44,11 @@ pub struct Module { impl Module { pub fn default_with_constants( + type_engine: &TypeEngine, constants: BTreeMap, ) -> Result> { let handler = <_>::default(); - Module::default_with_constants_inner(&handler, constants).map_err(|_| { + Module::default_with_constants_inner(&handler, type_engine, constants).map_err(|_| { let (errors, warnings) = handler.consume(); assert!(warnings.is_empty()); @@ -58,6 +59,7 @@ impl Module { fn default_with_constants_inner( handler: &Handler, + type_engine: &TypeEngine, constants: BTreeMap, ) -> Result { // it would be nice to one day maintain a span from the manifest file, but @@ -92,7 +94,10 @@ impl Module { let attributes = Default::default(); // convert to const decl let const_decl = to_parsed_lang::item_const_to_constant_declaration( - handler, const_item, attributes, + handler, + type_engine, + const_item, + attributes, )?; // Temporarily disallow non-literals. See https://github.com/FuelLabs/sway/issues/2647. @@ -109,7 +114,7 @@ impl Module { span: const_item_span.clone(), }; let mut ns = Namespace::init_root(Default::default()); - let type_check_ctx = TypeCheckContext::from_root(&mut ns); + let type_check_ctx = TypeCheckContext::from_root(&mut ns, type_engine); let typed_node = ty::TyAstNode::type_check(type_check_ctx, ast_node) .unwrap(&mut vec![], &mut vec![]); // get the decl out of the typed node: @@ -184,7 +189,12 @@ impl Module { /// This is used when an import path contains an asterisk. /// /// Paths are assumed to be relative to `self`. - pub(crate) fn star_import(&mut self, src: &Path, dst: &Path) -> CompileResult<()> { + pub(crate) fn star_import( + &mut self, + src: &Path, + dst: &Path, + type_engine: &TypeEngine, + ) -> CompileResult<()> { let mut warnings = vec![]; let mut errors = vec![]; let src_ns = check!( @@ -209,7 +219,9 @@ impl Module { } let dst_ns = &mut self[dst]; - dst_ns.implemented_traits.extend(implemented_traits); + dst_ns + .implemented_traits + .extend(implemented_traits, type_engine); for symbol in symbols { dst_ns .use_synonyms @@ -225,7 +237,12 @@ impl Module { /// This is used when an import path contains an asterisk. /// /// Paths are assumed to be relative to `self`. - pub fn star_import_with_reexports(&mut self, src: &Path, dst: &Path) -> CompileResult<()> { + pub fn star_import_with_reexports( + &mut self, + src: &Path, + dst: &Path, + type_engine: &TypeEngine, + ) -> CompileResult<()> { let mut warnings = vec![]; let mut errors = vec![]; let src_ns = check!( @@ -251,7 +268,9 @@ impl Module { } let dst_ns = &mut self[dst]; - dst_ns.implemented_traits.extend(implemented_traits); + dst_ns + .implemented_traits + .extend(implemented_traits, type_engine); let mut try_add = |symbol, path| { dst_ns.use_synonyms.insert(symbol, (path, GlobImport::Yes)); }; @@ -279,12 +298,13 @@ impl Module { /// import. pub(crate) fn self_import( &mut self, + type_engine: &TypeEngine, src: &Path, dst: &Path, alias: Option, ) -> CompileResult<()> { let (last_item, src) = src.split_last().expect("guaranteed by grammar"); - self.item_import(src, last_item, dst, alias) + self.item_import(type_engine, src, last_item, dst, alias) } /// Pull a single `item` from the given `src` module and import it into the `dst` module. @@ -292,6 +312,7 @@ impl Module { /// Paths are assumed to be relative to `self`. pub(crate) fn item_import( &mut self, + type_engine: &TypeEngine, src: &Path, item: &Ident, dst: &Path, @@ -328,13 +349,14 @@ impl Module { return ok((), warnings, errors); } } - let type_id = decl.return_type(&item.span()).value; + let type_id = decl.return_type(&item.span(), type_engine).value; // if this is an enum or struct or function, import its implementations if let Some(type_id) = type_id { impls_to_insert.extend( src_ns .implemented_traits - .filter_by_type_item_import(type_id), + .filter_by_type_item_import(type_id, type_engine), + type_engine, ); } // no matter what, import it this way though. @@ -364,7 +386,9 @@ impl Module { }; let dst_ns = &mut self[dst]; - dst_ns.implemented_traits.extend(impls_to_insert); + dst_ns + .implemented_traits + .extend(impls_to_insert, type_engine); ok((), warnings, errors) } diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index de51627cf24..81ccd119f4c 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -14,7 +14,7 @@ use sway_types::{span::Span, Spanned}; use std::collections::VecDeque; /// The set of items that represent the namespace context passed throughout type checking. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct Namespace { /// An immutable namespace that consists of the names that should always be present, no matter /// what module or scope we are currently checking. @@ -104,6 +104,7 @@ impl Namespace { /// Short-hand for calling [Root::resolve_type_with_self] on `root` with the `mod_path`. pub(crate) fn resolve_type_with_self( &mut self, + type_engine: &TypeEngine, type_id: TypeId, self_type: TypeId, span: &Span, @@ -111,7 +112,7 @@ impl Namespace { type_info_prefix: Option<&Path>, ) -> CompileResult { let mod_path = self.mod_path.clone(); - resolve_type_with_self( + type_engine.resolve_type_with_self( type_id, self_type, span, @@ -125,12 +126,13 @@ impl Namespace { /// Short-hand for calling [Root::resolve_type_without_self] on `root` and with the `mod_path`. pub(crate) fn resolve_type_without_self( &mut self, + type_engine: &TypeEngine, type_id: TypeId, span: &Span, type_info_prefix: Option<&Path>, ) -> CompileResult { let mod_path = self.mod_path.clone(); - resolve_type( + type_engine.resolve_type( type_id, span, EnforceTypeArguments::Yes, @@ -154,6 +156,7 @@ impl Namespace { method_name: &Ident, self_type: TypeId, args_buf: &VecDeque, + type_engine: &TypeEngine, ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; @@ -167,13 +170,13 @@ impl Namespace { ); // grab the local methods from the local module - let local_methods = local_module.get_methods_for_type(type_id); + let local_methods = local_module.get_methods_for_type(type_engine, type_id); - type_id.replace_self_type(self_type); + type_id.replace_self_type(type_engine, self_type); // resolve the type let type_id = check!( - resolve_type( + type_engine.resolve_type( type_id, &method_name.span(), EnforceTypeArguments::No, @@ -181,7 +184,7 @@ impl Namespace { self, method_prefix ), - insert_type(TypeInfo::ErrorRecovery), + type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors ); @@ -195,7 +198,7 @@ impl Namespace { ); // grab the methods from where the type is declared - let mut type_methods = type_module.get_methods_for_type(type_id); + let mut type_methods = type_module.get_methods_for_type(type_engine, type_id); let mut methods = local_methods; methods.append(&mut type_methods); @@ -211,16 +214,19 @@ impl Namespace { // if we find the method that we are looking for, we also need // to retrieve the impl definitions for the return type so that // the user can string together method calls - self.insert_trait_implementation_for_type(method.return_type); + self.insert_trait_implementation_for_type(type_engine, method.return_type); return ok(decl_id, warnings, errors); } } - if args_buf.get(0).map(|x| look_up_type_id(x.return_type)) != Some(TypeInfo::ErrorRecovery) + if !args_buf + .get(0) + .map(|x| type_engine.look_up_type_id(x.return_type)) + .eq(&Some(TypeInfo::ErrorRecovery), type_engine) { errors.push(CompileError::MethodNotFound { method_name: method_name.clone(), - type_name: type_id.to_string(), + type_name: type_engine.help_out(type_id).to_string(), span: method_name.span(), }); } @@ -228,23 +234,35 @@ impl Namespace { } /// Short-hand for performing a [Module::star_import] with `mod_path` as the destination. - pub(crate) fn star_import(&mut self, src: &Path) -> CompileResult<()> { - self.root.star_import(src, &self.mod_path) + pub(crate) fn star_import( + &mut self, + src: &Path, + type_engine: &TypeEngine, + ) -> CompileResult<()> { + self.root.star_import(src, &self.mod_path, type_engine) } /// Short-hand for performing a [Module::self_import] with `mod_path` as the destination. - pub(crate) fn self_import(&mut self, src: &Path, alias: Option) -> CompileResult<()> { - self.root.self_import(src, &self.mod_path, alias) + pub(crate) fn self_import( + &mut self, + type_engine: &TypeEngine, + src: &Path, + alias: Option, + ) -> CompileResult<()> { + self.root + .self_import(type_engine, src, &self.mod_path, alias) } /// Short-hand for performing a [Module::item_import] with `mod_path` as the destination. pub(crate) fn item_import( &mut self, + type_engine: &TypeEngine, src: &Path, item: &Ident, alias: Option, ) -> CompileResult<()> { - self.root.item_import(src, item, &self.mod_path, alias) + self.root + .item_import(type_engine, src, item, &self.mod_path, alias) } /// "Enter" the submodule at the given path by returning a new [SubmoduleNamespace]. diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 4b1414f15fb..3b91df4a014 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -13,7 +13,7 @@ use super::{module::Module, namespace::Namespace, Path}; /// canonical paths, or that use canonical paths internally, are *only* called from the root. This /// normally includes methods that first lookup some canonical path via `use_synonyms` before using /// that canonical path to look up the symbol declaration. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct Root { pub(crate) module: Module, } diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 5f1bdfe51b2..c867cfe211a 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -6,23 +6,79 @@ use sway_types::{Ident, Span, Spanned}; use crate::{ declaration_engine::{de_get_function, de_insert, de_look_up_decl_id, DeclarationId}, error::*, - insert_type, language::CallPath, - type_system::{look_up_type_id, CopyTypes, TypeId}, - ReplaceSelfType, TraitConstraint, TypeArgument, TypeInfo, TypeMapping, + type_system::{CopyTypes, TypeId}, + OrdWithTypeEngine, PartialEqWithTypeEngine, ReplaceSelfType, TraitConstraint, TypeArgument, + TypeEngine, TypeInfo, TypeMapping, }; -type TraitName = CallPath<(Ident, Vec)>; +#[derive(Clone, Debug)] +struct TraitSuffix { + name: Ident, + args: Vec, +} +impl PartialEqWithTypeEngine for TraitSuffix { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.name == rhs.name && self.args.eq(&rhs.args, type_engine) + } +} +impl OrdWithTypeEngine for TraitSuffix { + fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering { + self.name + .cmp(&rhs.name) + .then_with(|| self.args.cmp(&rhs.args, type_engine)) + } +} + +impl PartialEqWithTypeEngine for CallPath { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.prefixes == rhs.prefixes + && self.suffix.eq(&rhs.suffix, type_engine) + && self.is_absolute == rhs.is_absolute + } +} +impl OrdWithTypeEngine for CallPath { + fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering { + self.prefixes + .cmp(&rhs.prefixes) + .then_with(|| self.suffix.cmp(&rhs.suffix, type_engine)) + .then_with(|| self.is_absolute.cmp(&rhs.is_absolute)) + } +} + +type TraitName = CallPath; + +#[derive(Clone, Debug)] +struct TraitKey { + name: TraitName, + type_id: TypeId, +} + +impl OrdWithTypeEngine for TraitKey { + fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> std::cmp::Ordering { + self.name + .cmp(&rhs.name, type_engine) + .then_with(|| self.type_id.cmp(&rhs.type_id)) + } +} + /// Map of function name to [TyFunctionDeclaration](ty::TyFunctionDeclaration) type TraitMethods = im::HashMap; + +#[derive(Clone, Debug)] +struct TraitEntry { + key: TraitKey, + value: TraitMethods, +} + /// Map of trait name and type to [TraitMethods]. -type TraitImpls = im::OrdMap<(TraitName, TypeId), TraitMethods>; +type TraitImpls = Vec; /// Map holding trait implementations for types. /// /// Note: "impl self" blocks are considered traits and are stored in the /// [TraitMap]. -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default)] pub(crate) struct TraitMap { trait_impls: TraitImpls, } @@ -36,6 +92,7 @@ impl TraitMap { /// [TraitMap], and tries to append `methods` to an existing list of /// [TyFunctionDeclaration](ty::TyFunctionDeclaration) for the key /// `(trait_name, type_id)` whenever possible. + #[allow(clippy::too_many_arguments)] pub(crate) fn insert( &mut self, trait_name: CallPath, @@ -44,6 +101,7 @@ impl TraitMap { methods: &[DeclarationId], impl_span: &Span, is_impl_self: bool, + type_engine: &TypeEngine, ) -> CompileResult<()> { let mut warnings = vec![]; let mut errors = vec![]; @@ -60,7 +118,7 @@ impl TraitMap { } // check to see if adding this trait will produce a conflicting definition - let trait_type_id = insert_type(TypeInfo::Custom { + let trait_type_id = type_engine.insert_type(TypeInfo::Custom { name: trait_name.suffix.clone(), type_arguments: if trait_type_args.is_empty() { None @@ -68,12 +126,24 @@ impl TraitMap { Some(trait_type_args.clone()) }, }); - for ((map_trait_name, map_type_id), map_trait_methods) in self.trait_impls.iter() { + for TraitEntry { + key: + TraitKey { + name: map_trait_name, + type_id: map_type_id, + }, + value: map_trait_methods, + } in self.trait_impls.iter() + { let CallPath { - suffix: (map_trait_name_suffix, map_trait_type_args), + suffix: + TraitSuffix { + name: map_trait_name_suffix, + args: map_trait_type_args, + }, .. } = map_trait_name; - let map_trait_type_id = insert_type(TypeInfo::Custom { + let map_trait_type_id = type_engine.insert_type(TypeInfo::Custom { name: map_trait_name_suffix.clone(), type_arguments: if map_trait_type_args.is_empty() { None @@ -82,10 +152,12 @@ impl TraitMap { }, }); - let types_are_subset = - look_up_type_id(type_id).is_subset_of(&look_up_type_id(*map_type_id)); - let traits_are_subset = - look_up_type_id(trait_type_id).is_subset_of(&look_up_type_id(map_trait_type_id)); + let types_are_subset = type_engine + .look_up_type_id(type_id) + .is_subset_of(&type_engine.look_up_type_id(*map_type_id), type_engine); + let traits_are_subset = type_engine + .look_up_type_id(trait_type_id) + .is_subset_of(&type_engine.look_up_type_id(map_trait_type_id), type_engine); if types_are_subset && traits_are_subset && !is_impl_self { let trait_name_str = format!( @@ -98,7 +170,7 @@ impl TraitMap { "<{}>", trait_type_args .iter() - .map(|type_arg| type_arg.to_string()) + .map(|type_arg| type_engine.help_out(type_arg).to_string()) .collect::>() .join(", ") ) @@ -106,7 +178,7 @@ impl TraitMap { ); errors.push(CompileError::ConflictingImplsForTraitAndType { trait_name: trait_name_str, - type_implementing_for: type_id.to_string(), + type_implementing_for: type_engine.help_out(type_id).to_string(), second_impl_span: impl_span.clone(), }); } else if types_are_subset { @@ -120,7 +192,7 @@ impl TraitMap { ); errors.push(CompileError::DuplicateMethodsDefinedForType { func_name: method.name.to_string(), - type_implementing_for: type_id.to_string(), + type_implementing_for: type_engine.help_out(type_id).to_string(), span: method.name.span(), }); } @@ -129,12 +201,15 @@ impl TraitMap { } let trait_name: TraitName = CallPath { prefixes: trait_name.prefixes, - suffix: (trait_name.suffix, trait_type_args), + suffix: TraitSuffix { + name: trait_name.suffix, + args: trait_type_args, + }, is_absolute: trait_name.is_absolute, }; // even if there is a conflicting definition, add the trait anyway - self.insert_inner(trait_name, type_id, trait_methods); + self.insert_inner(trait_name, type_id, trait_methods, type_engine); if errors.is_empty() { ok((), warnings, errors) @@ -148,11 +223,20 @@ impl TraitMap { trait_name: TraitName, type_id: TypeId, trait_methods: TraitMethods, + type_engine: &TypeEngine, ) { - let trait_impls: TraitImpls = - std::iter::once(((trait_name, type_id), trait_methods)).collect(); + let key = TraitKey { + name: trait_name, + type_id, + }; + let entry = TraitEntry { + key, + value: trait_methods, + }; + let trait_impls: TraitImpls = vec![entry]; let trait_map = TraitMap { trait_impls }; - self.extend(trait_map); + + self.extend(trait_map, type_engine); } /// Given a [TypeId] `type_id`, retrieves entries in the [TraitMap] `self` @@ -241,18 +325,22 @@ impl TraitMap { /// re-insert them under `type_id`. Moreover, the impl block for /// `Data` needs to be able to call methods that are defined in the /// impl block of `Data` - pub(crate) fn insert_for_type(&mut self, type_id: TypeId) { - self.extend(self.filter_by_type(type_id)); + pub(crate) fn insert_for_type(&mut self, type_engine: &TypeEngine, type_id: TypeId) { + self.extend(self.filter_by_type(type_id, type_engine), type_engine); } /// Given [TraitMap]s `self` and `other`, extend `self` with `other`, /// extending existing entries when possible. - pub(crate) fn extend(&mut self, other: TraitMap) { - for (key, other_trait_methods) in other.trait_impls.into_iter() { - self.trait_impls - .entry(key) - .or_insert(other_trait_methods.clone()) - .extend(other_trait_methods.into_iter()); + pub(crate) fn extend(&mut self, other: TraitMap, type_engine: &TypeEngine) { + for oe in other.trait_impls.into_iter() { + let pos = self + .trait_impls + .binary_search_by(|se| se.key.cmp(&oe.key, type_engine)); + + match pos { + Ok(pos) => self.trait_impls[pos].value.extend(oe.value.into_iter()), + Err(pos) => self.trait_impls.insert(pos, oe), + } } } @@ -363,14 +451,17 @@ impl TraitMap { /// have `Data: get_first(self) -> T` and /// `Data: get_second(self) -> T`, and we can create a new [TraitMap] /// with those entries for `Data`. - pub(crate) fn filter_by_type(&self, type_id: TypeId) -> TraitMap { + pub(crate) fn filter_by_type(&self, type_id: TypeId, type_engine: &TypeEngine) -> TraitMap { // a curried version of the decider protocol to use in the helper functions - let decider = - |type_info: &TypeInfo, map_type_info: &TypeInfo| type_info.is_subset_of(map_type_info); - let mut all_types = look_up_type_id(type_id).extract_inner_types(); + let decider = |type_info: &TypeInfo, map_type_info: &TypeInfo| { + type_info.is_subset_of(map_type_info, type_engine) + }; + let mut all_types = type_engine + .look_up_type_id(type_id) + .extract_inner_types(type_engine); all_types.insert(type_id); let all_types = all_types.into_iter().collect::>(); - self.filter_by_type_inner(all_types, decider) + self.filter_by_type_inner(type_engine, all_types, decider) } /// Filters the entries in `self` with the given [TypeId] `type_id` and @@ -420,7 +511,7 @@ impl TraitMap { /// /// use my_point::MyPoint; /// - /// fn main() -> u64 { + /// fn main() -> u64 { /// let foo = MyPoint { /// x: 10u64, /// y: 10u64, @@ -431,54 +522,79 @@ impl TraitMap { /// /// We need to be able to import the trait defined upon `MyPoint` just /// from seeing `use ::my_double::MyDouble;`. - pub(crate) fn filter_by_type_item_import(&self, type_id: TypeId) -> TraitMap { + pub(crate) fn filter_by_type_item_import( + &self, + type_id: TypeId, + type_engine: &TypeEngine, + ) -> TraitMap { // a curried version of the decider protocol to use in the helper functions let decider = |type_info: &TypeInfo, map_type_info: &TypeInfo| { - type_info.is_subset_of(map_type_info) - || map_type_info.is_subset_of_for_item_import(type_info) + type_info.is_subset_of(map_type_info, type_engine) + || map_type_info.is_subset_of_for_item_import(type_info, type_engine) }; - let mut trait_map = self.filter_by_type_inner(vec![type_id], decider); - let all_types = look_up_type_id(type_id) - .extract_inner_types() + let mut trait_map = self.filter_by_type_inner(type_engine, vec![type_id], decider); + let all_types = type_engine + .look_up_type_id(type_id) + .extract_inner_types(type_engine) .into_iter() .collect::>(); // a curried version of the decider protocol to use in the helper functions - let decider2 = - |type_info: &TypeInfo, map_type_info: &TypeInfo| type_info.is_subset_of(map_type_info); - trait_map.extend(self.filter_by_type_inner(all_types, decider2)); + let decider2 = |type_info: &TypeInfo, map_type_info: &TypeInfo| { + type_info.is_subset_of(map_type_info, type_engine) + }; + trait_map.extend( + self.filter_by_type_inner(type_engine, all_types, decider2), + type_engine, + ); trait_map } - fn filter_by_type_inner(&self, mut all_types: Vec, decider: F) -> TraitMap - where - F: Fn(&TypeInfo, &TypeInfo) -> bool, - { + fn filter_by_type_inner( + &self, + type_engine: &TypeEngine, + mut all_types: Vec, + decider: impl Fn(&TypeInfo, &TypeInfo) -> bool, + ) -> TraitMap { let mut trait_map = TraitMap::default(); - for ((map_trait_name, map_type_id), map_trait_methods) in self.trait_impls.iter() { + for TraitEntry { + key: + TraitKey { + name: map_trait_name, + type_id: map_type_id, + }, + value: map_trait_methods, + } in self.trait_impls.iter() + { for type_id in all_types.iter_mut() { - let type_info = look_up_type_id(*type_id); + let type_info = type_engine.look_up_type_id(*type_id); if !type_info.can_change() && *type_id == *map_type_id { trait_map.insert_inner( map_trait_name.clone(), *type_id, map_trait_methods.clone(), + type_engine, ); - } else if decider(&type_info, &look_up_type_id(*map_type_id)) { + } else if decider(&type_info, &type_engine.look_up_type_id(*map_type_id)) { let type_mapping = - TypeMapping::from_superset_and_subset(*map_type_id, *type_id); - let new_self_type = insert_type(TypeInfo::SelfType); - type_id.replace_self_type(new_self_type); + TypeMapping::from_superset_and_subset(type_engine, *map_type_id, *type_id); + let new_self_type = type_engine.insert_type(TypeInfo::SelfType); + type_id.replace_self_type(type_engine, new_self_type); let trait_methods: TraitMethods = map_trait_methods .clone() .into_iter() .map(|(name, decl_id)| { let mut decl = de_look_up_decl_id(decl_id.clone()); - decl.copy_types(&type_mapping); - decl.replace_self_type(new_self_type); + decl.copy_types(&type_mapping, type_engine); + decl.replace_self_type(type_engine, new_self_type); (name, de_insert(decl, decl_id.span()).with_parent(decl_id)) }) .collect(); - trait_map.insert_inner(map_trait_name.clone(), *type_id, trait_methods); + trait_map.insert_inner( + map_trait_name.clone(), + *type_id, + trait_methods, + type_engine, + ); } } } @@ -489,20 +605,12 @@ impl TraitMap { /// types of the given `type_id`. This function is used when handling trait /// constraints and is coupled with `filter_by_type` and /// `filter_by_type_item_import`. - pub(crate) fn filter_against_type(&mut self, type_id: TypeId) { - // this collect is actually needed and causes an error if removed - #[allow(clippy::needless_collect)] - let filtered_keys = self - .trait_impls - .keys() - .cloned() - .filter(|(_, map_type_id)| { - look_up_type_id(type_id).is_subset_of(&look_up_type_id(*map_type_id)) - }) - .collect::>(); - for key in filtered_keys.into_iter() { - self.trait_impls.remove(&key); - } + pub(crate) fn filter_against_type(&mut self, type_engine: &TypeEngine, type_id: TypeId) { + self.trait_impls.retain(|e| { + !type_engine + .look_up_type_id(type_id) + .is_subset_of(&type_engine.look_up_type_id(e.key.type_id), type_engine) + }); } /// Find the entries in `self` that are equivalent to `type_id`. @@ -514,15 +622,23 @@ impl TraitMap { /// - this method does not translate types from the found entries to the /// `type_id` (like in `filter_by_type()`). This is because the only /// entries that qualify as hits are equivalents of `type_id` - pub(crate) fn get_methods_for_type(&self, type_id: TypeId) -> Vec { + pub(crate) fn get_methods_for_type( + &self, + type_engine: &TypeEngine, + type_id: TypeId, + ) -> Vec { let mut methods = vec![]; // small performance gain in bad case - if look_up_type_id(type_id) == TypeInfo::ErrorRecovery { + if type_engine + .look_up_type_id(type_id) + .eq(&TypeInfo::ErrorRecovery, type_engine) + { return methods; } - for ((_, map_type_id), map_trait_methods) in self.trait_impls.iter() { - if are_equal_minus_dynamic_types(type_id, *map_type_id) { - let mut trait_methods = map_trait_methods + for entry in self.trait_impls.iter() { + if are_equal_minus_dynamic_types(type_engine, type_id, entry.key.type_id) { + let mut trait_methods = entry + .value .values() .cloned() .into_iter() @@ -545,27 +661,28 @@ impl TraitMap { /// entries that qualify as hits are equivalents of `type_id` pub(crate) fn get_methods_for_type_and_trait_name( &self, + type_engine: &TypeEngine, type_id: TypeId, trait_name: &CallPath, ) -> Vec { let mut methods = vec![]; // small performance gain in bad case - if look_up_type_id(type_id) == TypeInfo::ErrorRecovery { + if type_engine + .look_up_type_id(type_id) + .eq(&TypeInfo::ErrorRecovery, type_engine) + { return methods; } - for ((map_trait_name, map_type_id), map_trait_methods) in self.trait_impls.iter() { + for e in self.trait_impls.iter() { let map_trait_name = CallPath { - prefixes: map_trait_name.prefixes.clone(), - suffix: map_trait_name.suffix.0.clone(), - is_absolute: map_trait_name.is_absolute, + prefixes: e.key.name.prefixes.clone(), + suffix: e.key.name.suffix.name.clone(), + is_absolute: e.key.name.is_absolute, }; - if &map_trait_name == trait_name && are_equal_minus_dynamic_types(type_id, *map_type_id) + if &map_trait_name == trait_name + && are_equal_minus_dynamic_types(type_engine, type_id, e.key.type_id) { - let mut trait_methods = map_trait_methods - .values() - .cloned() - .into_iter() - .collect::>(); + let mut trait_methods = e.value.values().cloned().into_iter().collect::>(); methods.append(&mut trait_methods); } } @@ -578,6 +695,7 @@ impl TraitMap { type_id: TypeId, constraints: &[TraitConstraint], access_span: &Span, + type_engine: &TypeEngine, ) -> CompileResult<()> { let warnings = vec![]; let mut errors = vec![]; @@ -594,7 +712,7 @@ impl TraitMap { trait_name: constraint_trait_name, type_arguments: constraint_type_arguments, } = constraint; - let constraint_type_id = insert_type(TypeInfo::Custom { + let constraint_type_id = type_engine.insert_type(TypeInfo::Custom { name: constraint_trait_name.suffix.clone(), type_arguments: if constraint_type_arguments.is_empty() { None @@ -602,21 +720,22 @@ impl TraitMap { Some(constraint_type_arguments.clone()) }, }); - for (map_trait_name, map_type_id) in self.trait_impls.keys() { - let CallPath { - suffix: (map_trait_name_suffix, map_trait_type_args), - .. - } = map_trait_name; - let map_trait_type_id = insert_type(TypeInfo::Custom { - name: map_trait_name_suffix.clone(), - type_arguments: if map_trait_type_args.is_empty() { + for key in self.trait_impls.iter().map(|e| &e.key) { + let suffix = &key.name.suffix; + let map_trait_type_id = type_engine.insert_type(TypeInfo::Custom { + name: suffix.name.clone(), + type_arguments: if suffix.args.is_empty() { None } else { - Some(map_trait_type_args.to_vec()) + Some(suffix.args.to_vec()) }, }); - if are_equal_minus_dynamic_types(type_id, *map_type_id) - && are_equal_minus_dynamic_types(constraint_type_id, map_trait_type_id) + if are_equal_minus_dynamic_types(type_engine, type_id, key.type_id) + && are_equal_minus_dynamic_types( + type_engine, + constraint_type_id, + map_trait_type_id, + ) { found_traits.insert(constraint_trait_name.suffix.clone()); } @@ -626,7 +745,7 @@ impl TraitMap { for trait_name in required_traits.difference(&found_traits) { // TODO: use a better span errors.push(CompileError::TraitConstraintNotSatisfied { - ty: type_id.to_string(), + ty: type_engine.help_out(type_id).to_string(), trait_name: trait_name.to_string(), span: access_span.clone(), }); @@ -640,11 +759,14 @@ impl TraitMap { } } -fn are_equal_minus_dynamic_types(left: TypeId, right: TypeId) -> bool { - if *left == *right { +fn are_equal_minus_dynamic_types(type_engine: &TypeEngine, left: TypeId, right: TypeId) -> bool { + if left.index() == right.index() { return true; } - match (look_up_type_id(left), look_up_type_id(right)) { + match ( + type_engine.look_up_type_id(left), + type_engine.look_up_type_id(right), + ) { // these cases are false because, unless left and right have the same // TypeId, they may later resolve to be different types in the type // engine @@ -681,7 +803,11 @@ fn are_equal_minus_dynamic_types(left: TypeId, right: TypeId) -> bool { .iter() .zip(r_type_args.unwrap_or_default().iter()) .fold(true, |acc, (left, right)| { - acc && are_equal_minus_dynamic_types(left.type_id, right.type_id) + acc && are_equal_minus_dynamic_types( + type_engine, + left.type_id, + right.type_id, + ) }) } ( @@ -701,14 +827,22 @@ fn are_equal_minus_dynamic_types(left: TypeId, right: TypeId) -> bool { true, |acc, (left, right)| { acc && left.name == right.name - && are_equal_minus_dynamic_types(left.type_id, right.type_id) + && are_equal_minus_dynamic_types( + type_engine, + left.type_id, + right.type_id, + ) }, ) && l_type_parameters.iter().zip(r_type_parameters.iter()).fold( true, |acc, (left, right)| { acc && left.name_ident == right.name_ident - && are_equal_minus_dynamic_types(left.type_id, right.type_id) + && are_equal_minus_dynamic_types( + type_engine, + left.type_id, + right.type_id, + ) }, ) } @@ -730,19 +864,27 @@ fn are_equal_minus_dynamic_types(left: TypeId, right: TypeId) -> bool { .zip(r_fields.iter()) .fold(true, |acc, (left, right)| { acc && left.name == right.name - && are_equal_minus_dynamic_types(left.type_id, right.type_id) + && are_equal_minus_dynamic_types( + type_engine, + left.type_id, + right.type_id, + ) }) && l_type_parameters.iter().zip(r_type_parameters.iter()).fold( true, |acc, (left, right)| { acc && left.name_ident == right.name_ident - && are_equal_minus_dynamic_types(left.type_id, right.type_id) + && are_equal_minus_dynamic_types( + type_engine, + left.type_id, + right.type_id, + ) }, ) } (TypeInfo::Tuple(l), TypeInfo::Tuple(r)) => { l.iter().zip(r.iter()).fold(true, |acc, (left, right)| { - acc && are_equal_minus_dynamic_types(left.type_id, right.type_id) + acc && are_equal_minus_dynamic_types(type_engine, left.type_id, right.type_id) }) } ( @@ -758,12 +900,16 @@ fn are_equal_minus_dynamic_types(left: TypeId, right: TypeId) -> bool { l_abi_name == r_abi_name && Option::zip(l_address, r_address) .map(|(l_address, r_address)| { - are_equal_minus_dynamic_types(l_address.return_type, r_address.return_type) + are_equal_minus_dynamic_types( + type_engine, + l_address.return_type, + r_address.return_type, + ) }) .unwrap_or(true) } (TypeInfo::Array(l0, l1, _), TypeInfo::Array(r0, r1, _)) => { - l1 == r1 && are_equal_minus_dynamic_types(l0, r0) + l1 == r1 && are_equal_minus_dynamic_types(type_engine, l0, r0) } _ => false, } diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index 581e9df3cff..fb8d4c42ea8 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -2,10 +2,11 @@ use std::collections::{HashMap, HashSet}; use std::iter::FromIterator; use crate::type_system::{TypeArgument, TypeParameter}; +use crate::TypeEngine; use crate::{ error::*, language::{parsed::*, CallPath}, - type_system::{look_up_type_id, AbiName}, + type_system::AbiName, TypeInfo, }; @@ -18,9 +19,15 @@ use sway_types::{ident::Ident, span::Span}; /// Take a list of nodes and reorder them so that they may be semantically analysed without any /// dependencies breaking. -pub(crate) fn order_ast_nodes_by_dependency(nodes: Vec) -> CompileResult> { - let decl_dependencies = - DependencyMap::from_iter(nodes.iter().filter_map(Dependencies::gather_from_decl_node)); +pub(crate) fn order_ast_nodes_by_dependency( + type_engine: &TypeEngine, + nodes: Vec, +) -> CompileResult> { + let decl_dependencies = DependencyMap::from_iter( + nodes + .iter() + .filter_map(|node| Dependencies::gather_from_decl_node(type_engine, node)), + ); // Check here for recursive calls now that we have a nice map of the dependencies to help us. let mut errors = find_recursive_decls(&decl_dependencies); @@ -265,7 +272,10 @@ struct Dependencies { } impl Dependencies { - fn gather_from_decl_node(node: &AstNode) -> Option<(DependentSymbol, Dependencies)> { + fn gather_from_decl_node( + type_engine: &TypeEngine, + node: &AstNode, + ) -> Option<(DependentSymbol, Dependencies)> { match &node.content { AstNodeContent::Declaration(decl) => decl_name(decl).map(|name| { ( @@ -273,37 +283,39 @@ impl Dependencies { Dependencies { deps: HashSet::new(), } - .gather_from_decl(decl), + .gather_from_decl(type_engine, decl), ) }), _ => None, } } - fn gather_from_decl(self, decl: &Declaration) -> Self { + fn gather_from_decl(self, type_engine: &TypeEngine, decl: &Declaration) -> Self { match decl { Declaration::VariableDeclaration(VariableDeclaration { type_ascription, body, .. }) => self - .gather_from_typeinfo(type_ascription) - .gather_from_expr(body), + .gather_from_typeinfo(type_engine, type_ascription) + .gather_from_expr(type_engine, body), Declaration::ConstantDeclaration(ConstantDeclaration { type_ascription, value, .. }) => self - .gather_from_typeinfo(type_ascription) - .gather_from_expr(value), - Declaration::FunctionDeclaration(fn_decl) => self.gather_from_fn_decl(fn_decl), + .gather_from_typeinfo(type_engine, type_ascription) + .gather_from_expr(type_engine, value), + Declaration::FunctionDeclaration(fn_decl) => { + self.gather_from_fn_decl(type_engine, fn_decl) + } Declaration::StructDeclaration(StructDeclaration { fields, type_parameters, .. }) => self .gather_from_iter(fields.iter(), |deps, field| { - deps.gather_from_typeinfo(&field.type_info) + deps.gather_from_typeinfo(type_engine, &field.type_info) }) .gather_from_type_parameters(type_parameters), Declaration::EnumDeclaration(EnumDeclaration { @@ -312,7 +324,7 @@ impl Dependencies { .. }) => self .gather_from_iter(variants.iter(), |deps, variant| { - deps.gather_from_typeinfo(&variant.type_info) + deps.gather_from_typeinfo(type_engine, &variant.type_info) }) .gather_from_type_parameters(type_parameters), Declaration::TraitDeclaration(TraitDeclaration { @@ -326,12 +338,12 @@ impl Dependencies { }) .gather_from_iter(interface_surface.iter(), |deps, sig| { deps.gather_from_iter(sig.parameters.iter(), |deps, param| { - deps.gather_from_typeinfo(¶m.type_info) + deps.gather_from_typeinfo(type_engine, ¶m.type_info) }) - .gather_from_typeinfo(&sig.return_type) + .gather_from_typeinfo(type_engine, &sig.return_type) }) .gather_from_iter(methods.iter(), |deps, fn_decl| { - deps.gather_from_fn_decl(fn_decl) + deps.gather_from_fn_decl(type_engine, fn_decl) }), Declaration::ImplTrait(ImplTrait { impl_type_parameters, @@ -341,19 +353,19 @@ impl Dependencies { .. }) => self .gather_from_call_path(trait_name, false, false) - .gather_from_typeinfo(type_implementing_for) + .gather_from_typeinfo(type_engine, type_implementing_for) .gather_from_type_parameters(impl_type_parameters) .gather_from_iter(functions.iter(), |deps, fn_decl| { - deps.gather_from_fn_decl(fn_decl) + deps.gather_from_fn_decl(type_engine, fn_decl) }), Declaration::ImplSelf(ImplSelf { type_implementing_for, functions, .. }) => self - .gather_from_typeinfo(type_implementing_for) + .gather_from_typeinfo(type_engine, type_implementing_for) .gather_from_iter(functions.iter(), |deps, fn_decl| { - deps.gather_from_fn_decl(fn_decl) + deps.gather_from_fn_decl(type_engine, fn_decl) }), Declaration::AbiDeclaration(AbiDeclaration { interface_surface, @@ -362,21 +374,21 @@ impl Dependencies { }) => self .gather_from_iter(interface_surface.iter(), |deps, sig| { deps.gather_from_iter(sig.parameters.iter(), |deps, param| { - deps.gather_from_typeinfo(¶m.type_info) + deps.gather_from_typeinfo(type_engine, ¶m.type_info) }) - .gather_from_typeinfo(&sig.return_type) + .gather_from_typeinfo(type_engine, &sig.return_type) }) .gather_from_iter(methods.iter(), |deps, fn_decl| { - deps.gather_from_fn_decl(fn_decl) + deps.gather_from_fn_decl(type_engine, fn_decl) }), Declaration::StorageDeclaration(StorageDeclaration { fields, .. }) => self .gather_from_iter(fields.iter(), |deps, StorageField { ref type_info, .. }| { - deps.gather_from_typeinfo(type_info) + deps.gather_from_typeinfo(type_engine, type_info) }), } } - fn gather_from_fn_decl(self, fn_decl: &FunctionDeclaration) -> Self { + fn gather_from_fn_decl(self, type_engine: &TypeEngine, fn_decl: &FunctionDeclaration) -> Self { let FunctionDeclaration { parameters, return_type, @@ -385,14 +397,14 @@ impl Dependencies { .. } = fn_decl; self.gather_from_iter(parameters.iter(), |deps, param| { - deps.gather_from_typeinfo(¶m.type_info) + deps.gather_from_typeinfo(type_engine, ¶m.type_info) }) - .gather_from_typeinfo(return_type) - .gather_from_block(body) + .gather_from_typeinfo(type_engine, return_type) + .gather_from_block(type_engine, body) .gather_from_type_parameters(type_parameters) } - fn gather_from_expr(self, expr: &Expression) -> Self { + fn gather_from_expr(self, type_engine: &TypeEngine, expr: &Expression) -> Self { match &expr.kind { ExpressionKind::Variable(name) => { // in the case of ABI variables, we actually want to check if the ABI needs to be @@ -405,51 +417,54 @@ impl Dependencies { arguments, } = &**function_application_expression; self.gather_from_call_path(&call_path_binding.inner, false, true) - .gather_from_type_arguments(&call_path_binding.type_arguments) - .gather_from_iter(arguments.iter(), |deps, arg| deps.gather_from_expr(arg)) - } - ExpressionKind::LazyOperator(LazyOperatorExpression { lhs, rhs, .. }) => { - self.gather_from_expr(lhs).gather_from_expr(rhs) + .gather_from_type_arguments(type_engine, &call_path_binding.type_arguments) + .gather_from_iter(arguments.iter(), |deps, arg| { + deps.gather_from_expr(type_engine, arg) + }) } + ExpressionKind::LazyOperator(LazyOperatorExpression { lhs, rhs, .. }) => self + .gather_from_expr(type_engine, lhs) + .gather_from_expr(type_engine, rhs), ExpressionKind::If(IfExpression { condition, then, r#else, .. }) => if let Some(else_expr) = r#else { - self.gather_from_expr(else_expr) + self.gather_from_expr(type_engine, else_expr) } else { self } - .gather_from_expr(condition) - .gather_from_expr(then), + .gather_from_expr(type_engine, condition) + .gather_from_expr(type_engine, then), ExpressionKind::Match(MatchExpression { value, branches, .. }) => self - .gather_from_expr(value) + .gather_from_expr(type_engine, value) .gather_from_iter(branches.iter(), |deps, branch| { - deps.gather_from_match_branch(branch) + deps.gather_from_match_branch(type_engine, branch) }), - ExpressionKind::CodeBlock(contents) => self.gather_from_block(contents), - ExpressionKind::Array(contents) => { - self.gather_from_iter(contents.iter(), |deps, expr| deps.gather_from_expr(expr)) - } - ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index, .. }) => { - self.gather_from_expr(prefix).gather_from_expr(index) - } + ExpressionKind::CodeBlock(contents) => self.gather_from_block(type_engine, contents), + ExpressionKind::Array(contents) => self + .gather_from_iter(contents.iter(), |deps, expr| { + deps.gather_from_expr(type_engine, expr) + }), + ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index, .. }) => self + .gather_from_expr(type_engine, prefix) + .gather_from_expr(type_engine, index), ExpressionKind::Struct(struct_expression) => { let StructExpression { call_path_binding, fields, } = &**struct_expression; self.gather_from_call_path(&call_path_binding.inner, false, false) - .gather_from_type_arguments(&call_path_binding.type_arguments) + .gather_from_type_arguments(type_engine, &call_path_binding.type_arguments) .gather_from_iter(fields.iter(), |deps, field| { - deps.gather_from_expr(&field.value) + deps.gather_from_expr(type_engine, &field.value) }) } ExpressionKind::Subfield(SubfieldExpression { prefix, .. }) => { - self.gather_from_expr(prefix) + self.gather_from_expr(type_engine, prefix) } ExpressionKind::AmbiguousPathExpression(e) => { let AmbiguousPathExpression { @@ -465,8 +480,10 @@ impl Dependencies { call_path_binding.inner.suffix.before.inner.clone(), )); } - this.gather_from_type_arguments(&call_path_binding.type_arguments) - .gather_from_iter(args.iter(), |deps, arg| deps.gather_from_expr(arg)) + this.gather_from_type_arguments(type_engine, &call_path_binding.type_arguments) + .gather_from_iter(args.iter(), |deps, arg| { + deps.gather_from_expr(type_engine, arg) + }) } ExpressionKind::DelineatedPath(delineated_path_expression) => { let DelineatedPathExpression { @@ -477,19 +494,21 @@ impl Dependencies { // case we're interested in the enum name and initialiser args, ignoring the // variant name. self.gather_from_call_path(&call_path_binding.inner, true, false) - .gather_from_type_arguments(&call_path_binding.type_arguments) - .gather_from_iter(args.iter(), |deps, arg| deps.gather_from_expr(arg)) + .gather_from_type_arguments(type_engine, &call_path_binding.type_arguments) + .gather_from_iter(args.iter(), |deps, arg| { + deps.gather_from_expr(type_engine, arg) + }) } ExpressionKind::MethodApplication(method_application_expression) => self .gather_from_iter( method_application_expression.arguments.iter(), - |deps, arg| deps.gather_from_expr(arg), + |deps, arg| deps.gather_from_expr(type_engine, arg), ), ExpressionKind::Asm(asm) => self .gather_from_iter(asm.registers.iter(), |deps, register| { - deps.gather_from_opt_expr(register.initializer.as_ref()) + deps.gather_from_opt_expr(type_engine, register.initializer.as_ref()) }) - .gather_from_typeinfo(&asm.return_type), + .gather_from_typeinfo(type_engine, &asm.return_type), // we should do address someday, but due to the whole `re_parse_expression` thing // it isn't possible right now @@ -503,52 +522,60 @@ impl Dependencies { | ExpressionKind::StorageAccess(_) | ExpressionKind::Error(_) => self, - ExpressionKind::Tuple(fields) => { - self.gather_from_iter(fields.iter(), |deps, field| deps.gather_from_expr(field)) - } + ExpressionKind::Tuple(fields) => self.gather_from_iter(fields.iter(), |deps, field| { + deps.gather_from_expr(type_engine, field) + }), ExpressionKind::TupleIndex(TupleIndexExpression { prefix, .. }) => { - self.gather_from_expr(prefix) + self.gather_from_expr(type_engine, prefix) } ExpressionKind::IntrinsicFunction(IntrinsicFunctionExpression { arguments, .. - }) => self.gather_from_iter(arguments.iter(), |deps, arg| deps.gather_from_expr(arg)), + }) => self.gather_from_iter(arguments.iter(), |deps, arg| { + deps.gather_from_expr(type_engine, arg) + }), ExpressionKind::WhileLoop(WhileLoopExpression { condition, body, .. - }) => self.gather_from_expr(condition).gather_from_block(body), - ExpressionKind::Reassignment(reassignment) => self.gather_from_expr(&reassignment.rhs), - ExpressionKind::Return(expr) => self.gather_from_expr(expr), + }) => self + .gather_from_expr(type_engine, condition) + .gather_from_block(type_engine, body), + ExpressionKind::Reassignment(reassignment) => { + self.gather_from_expr(type_engine, &reassignment.rhs) + } + ExpressionKind::Return(expr) => self.gather_from_expr(type_engine, expr), } } - fn gather_from_match_branch(self, branch: &MatchBranch) -> Self { + fn gather_from_match_branch(self, type_engine: &TypeEngine, branch: &MatchBranch) -> Self { let MatchBranch { scrutinee, result, .. } = branch; self.gather_from_iter( scrutinee.gather_approximate_typeinfo_dependencies().iter(), - |deps, type_info| deps.gather_from_typeinfo(type_info), + |deps, type_info| deps.gather_from_typeinfo(type_engine, type_info), ) - .gather_from_expr(result) + .gather_from_expr(type_engine, result) } - fn gather_from_opt_expr(self, opt_expr: Option<&Expression>) -> Self { + fn gather_from_opt_expr(self, type_engine: &TypeEngine, opt_expr: Option<&Expression>) -> Self { match opt_expr { None => self, - Some(expr) => self.gather_from_expr(expr), + Some(expr) => self.gather_from_expr(type_engine, expr), } } - fn gather_from_block(self, block: &CodeBlock) -> Self { + fn gather_from_block(self, type_engine: &TypeEngine, block: &CodeBlock) -> Self { self.gather_from_iter(block.contents.iter(), |deps, node| { - deps.gather_from_node(node) + deps.gather_from_node(type_engine, node) }) } - fn gather_from_node(self, node: &AstNode) -> Self { + fn gather_from_node(self, type_engine: &TypeEngine, node: &AstNode) -> Self { match &node.content { - AstNodeContent::Expression(expr) => self.gather_from_expr(expr), - AstNodeContent::ImplicitReturnExpression(expr) => self.gather_from_expr(expr), - AstNodeContent::Declaration(decl) => self.gather_from_decl(decl), + AstNodeContent::Expression(expr) => self.gather_from_expr(type_engine, expr), + AstNodeContent::ImplicitReturnExpression(expr) => { + self.gather_from_expr(type_engine, expr) + } + AstNodeContent::Declaration(decl) => self.gather_from_decl(type_engine, decl), // No deps from these guys. AstNodeContent::UseStatement(_) => self, @@ -587,13 +614,20 @@ impl Dependencies { }) } - fn gather_from_type_arguments(self, type_arguments: &[TypeArgument]) -> Self { + fn gather_from_type_arguments( + self, + type_engine: &TypeEngine, + type_arguments: &[TypeArgument], + ) -> Self { self.gather_from_iter(type_arguments.iter(), |deps, type_argument| { - deps.gather_from_typeinfo(&look_up_type_id(type_argument.type_id)) + deps.gather_from_typeinfo( + type_engine, + &type_engine.look_up_type_id(type_argument.type_id), + ) }) } - fn gather_from_typeinfo(mut self, type_info: &TypeInfo) -> Self { + fn gather_from_typeinfo(mut self, type_engine: &TypeEngine, type_info: &TypeInfo) -> Self { match type_info { TypeInfo::ContractCaller { abi_name: AbiName::Known(abi_name), @@ -605,22 +639,34 @@ impl Dependencies { } => { self.deps.insert(DependentSymbol::Symbol(name.clone())); match type_arguments { - Some(type_arguments) => self.gather_from_type_arguments(type_arguments), + Some(type_arguments) => { + self.gather_from_type_arguments(type_engine, type_arguments) + } None => self, } } TypeInfo::Tuple(elems) => self.gather_from_iter(elems.iter(), |deps, elem| { - deps.gather_from_typeinfo(&look_up_type_id(elem.type_id)) + deps.gather_from_typeinfo(type_engine, &type_engine.look_up_type_id(elem.type_id)) }), - TypeInfo::Array(type_id, _, _) => self.gather_from_typeinfo(&look_up_type_id(*type_id)), - TypeInfo::Struct { fields, .. } => self - .gather_from_iter(fields.iter(), |deps, field| { - deps.gather_from_typeinfo(&look_up_type_id(field.type_id)) - }), - TypeInfo::Enum { variant_types, .. } => self - .gather_from_iter(variant_types.iter(), |deps, variant| { - deps.gather_from_typeinfo(&look_up_type_id(variant.type_id)) - }), + TypeInfo::Array(type_id, _, _) => { + self.gather_from_typeinfo(type_engine, &type_engine.look_up_type_id(*type_id)) + } + TypeInfo::Struct { fields, .. } => { + self.gather_from_iter(fields.iter(), |deps, field| { + deps.gather_from_typeinfo( + type_engine, + &type_engine.look_up_type_id(field.type_id), + ) + }) + } + TypeInfo::Enum { variant_types, .. } => { + self.gather_from_iter(variant_types.iter(), |deps, variant| { + deps.gather_from_typeinfo( + type_engine, + &type_engine.look_up_type_id(variant.type_id), + ) + }) + } _ => self, } } diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index b456b8615b7..ddf4eb3ba52 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -7,6 +7,7 @@ use crate::{ namespace::{self, Namespace}, TypeCheckContext, }, + TypeEngine, }; use sway_ir::{Context, Module}; use sway_types::Spanned; @@ -17,16 +18,17 @@ impl ty::TyProgram { /// The given `initial_namespace` acts as an initial state for each module within this program. /// It should contain a submodule for each library package dependency. pub fn type_check( + type_engine: &TypeEngine, parsed: &ParseProgram, initial_namespace: namespace::Module, ) -> CompileResult { let mut namespace = Namespace::init_root(initial_namespace); - let ctx = TypeCheckContext::from_root(&mut namespace); + let ctx = TypeCheckContext::from_root(&mut namespace, type_engine); let ParseProgram { root, kind } = parsed; let mod_span = root.tree.span.clone(); let mod_res = ty::TyModule::type_check(ctx, root); mod_res.flat_map(|root| { - let res = Self::validate_root(&root, kind.clone(), mod_span); + let res = Self::validate_root(type_engine, &root, kind.clone(), mod_span); res.map(|(kind, declarations)| Self { kind, root, @@ -39,6 +41,7 @@ impl ty::TyProgram { pub(crate) fn get_typed_program_with_initialized_storage_slots( self, + type_engine: &TypeEngine, context: &mut Context, md_mgr: &mut MetadataManager, module: Module, @@ -62,7 +65,12 @@ impl ty::TyProgram { errors ); let mut storage_slots = check!( - decl.get_initialized_storage_slots(context, md_mgr, module), + decl.get_initialized_storage_slots( + type_engine, + context, + md_mgr, + module + ), return err(warnings, errors), warnings, errors, diff --git a/sway-core/src/semantic_analysis/storage_only_types.rs b/sway-core/src/semantic_analysis/storage_only_types.rs index 69a503abb4f..c6bcf1e44f3 100644 --- a/sway-core/src/semantic_analysis/storage_only_types.rs +++ b/sway-core/src/semantic_analysis/storage_only_types.rs @@ -4,18 +4,18 @@ use sway_types::{Span, Spanned}; use crate::{declaration_engine::declaration_engine::*, error::*, language::ty, type_system::*}; -fn ast_node_validate(x: &ty::TyAstNodeContent) -> CompileResult<()> { +fn ast_node_validate(ty_engine: &TypeEngine, x: &ty::TyAstNodeContent) -> CompileResult<()> { let errors: Vec = vec![]; let warnings: Vec = vec![]; match x { ty::TyAstNodeContent::Expression(expr) - | ty::TyAstNodeContent::ImplicitReturnExpression(expr) => expr_validate(expr), - ty::TyAstNodeContent::Declaration(decl) => decl_validate(decl), + | ty::TyAstNodeContent::ImplicitReturnExpression(expr) => expr_validate(ty_engine, expr), + ty::TyAstNodeContent::Declaration(decl) => decl_validate(ty_engine, decl), ty::TyAstNodeContent::SideEffect => ok((), warnings, errors), } } -fn expr_validate(expr: &ty::TyExpression) -> CompileResult<()> { +fn expr_validate(ty_engine: &TypeEngine, expr: &ty::TyExpression) -> CompileResult<()> { let mut errors: Vec = vec![]; let mut warnings: Vec = vec![]; match &expr.expression { @@ -27,7 +27,7 @@ fn expr_validate(expr: &ty::TyExpression) -> CompileResult<()> { | ty::TyExpressionVariant::AbiName(_) => (), ty::TyExpressionVariant::FunctionApplication { arguments, .. } => { for f in arguments { - check!(expr_validate(&f.1), continue, warnings, errors); + check!(expr_validate(ty_engine, &f.1), continue, warnings, errors); } } ty::TyExpressionVariant::LazyOperator { @@ -39,8 +39,8 @@ fn expr_validate(expr: &ty::TyExpression) -> CompileResult<()> { prefix: expr1, index: expr2, } => { - check!(expr_validate(expr1), (), warnings, errors); - check!(expr_validate(expr2), (), warnings, errors); + check!(expr_validate(ty_engine, expr1), (), warnings, errors); + check!(expr_validate(ty_engine, expr2), (), warnings, errors); } ty::TyExpressionVariant::IntrinsicFunction(ty::TyIntrinsicFunctionKind { arguments: exprvec, @@ -49,17 +49,22 @@ fn expr_validate(expr: &ty::TyExpression) -> CompileResult<()> { | ty::TyExpressionVariant::Tuple { fields: exprvec } | ty::TyExpressionVariant::Array { contents: exprvec } => { for f in exprvec { - check!(expr_validate(f), continue, warnings, errors) + check!(expr_validate(ty_engine, f), continue, warnings, errors) } } ty::TyExpressionVariant::StructExpression { fields, .. } => { for f in fields { - check!(expr_validate(&f.value), continue, warnings, errors); + check!( + expr_validate(ty_engine, &f.value), + continue, + warnings, + errors + ); } } ty::TyExpressionVariant::CodeBlock(cb) => { check!( - validate_decls_for_storage_only_types_in_codeblock(cb), + validate_decls_for_storage_only_types_in_codeblock(ty_engine, cb), (), warnings, errors @@ -70,10 +75,10 @@ fn expr_validate(expr: &ty::TyExpression) -> CompileResult<()> { then, r#else, } => { - check!(expr_validate(condition), (), warnings, errors); - check!(expr_validate(then), (), warnings, errors); + check!(expr_validate(ty_engine, condition), (), warnings, errors); + check!(expr_validate(ty_engine, then), (), warnings, errors); if let Some(r#else) = r#else { - check!(expr_validate(r#else), (), warnings, errors); + check!(expr_validate(ty_engine, r#else), (), warnings, errors); } } ty::TyExpressionVariant::StructFieldAccess { prefix: exp, .. } @@ -81,17 +86,17 @@ fn expr_validate(expr: &ty::TyExpression) -> CompileResult<()> { | ty::TyExpressionVariant::AbiCast { address: exp, .. } | ty::TyExpressionVariant::EnumTag { exp } | ty::TyExpressionVariant::UnsafeDowncast { exp, .. } => { - check!(expr_validate(exp), (), warnings, errors) + check!(expr_validate(ty_engine, exp), (), warnings, errors) } ty::TyExpressionVariant::EnumInstantiation { contents, .. } => { if let Some(f) = contents { - check!(expr_validate(f), (), warnings, errors); + check!(expr_validate(ty_engine, f), (), warnings, errors); } } ty::TyExpressionVariant::WhileLoop { condition, body } => { - check!(expr_validate(condition), (), warnings, errors); + check!(expr_validate(ty_engine, condition), (), warnings, errors); check!( - validate_decls_for_storage_only_types_in_codeblock(body), + validate_decls_for_storage_only_types_in_codeblock(ty_engine, body), (), warnings, errors @@ -104,54 +109,59 @@ fn expr_validate(expr: &ty::TyExpression) -> CompileResult<()> { lhs_base_name, rhs, .. } = &**reassignment; check!( - check_type(rhs.return_type, lhs_base_name.span(), false), + check_type(ty_engine, rhs.return_type, lhs_base_name.span(), false), (), warnings, errors, ); - check!(expr_validate(rhs), (), warnings, errors) + check!(expr_validate(ty_engine, rhs), (), warnings, errors) } ty::TyExpressionVariant::StorageReassignment(storage_reassignment) => { let span = storage_reassignment.span(); let rhs = &storage_reassignment.rhs; check!( - check_type(rhs.return_type, span, false), + check_type(ty_engine, rhs.return_type, span, false), (), warnings, errors, ); - check!(expr_validate(rhs), (), warnings, errors) + check!(expr_validate(ty_engine, rhs), (), warnings, errors) } ty::TyExpressionVariant::Return(exp) => { - check!(expr_validate(exp), (), warnings, errors) + check!(expr_validate(ty_engine, exp), (), warnings, errors) } } ok((), warnings, errors) } -fn check_type(ty: TypeId, span: Span, ignore_self: bool) -> CompileResult<()> { +fn check_type( + ty_engine: &TypeEngine, + ty: TypeId, + span: Span, + ignore_self: bool, +) -> CompileResult<()> { let mut warnings: Vec = vec![]; let mut errors: Vec = vec![]; let type_info = check!( - CompileResult::from(to_typeinfo(ty, &span).map_err(CompileError::from)), + CompileResult::from(ty_engine.to_typeinfo(ty, &span).map_err(CompileError::from)), TypeInfo::ErrorRecovery, warnings, errors ); let nested_types = check!( - type_info.clone().extract_nested_types(&span), + type_info.clone().extract_nested_types(ty_engine, &span), vec![], warnings, errors ); for ty in nested_types { - if ignore_self && ty == type_info { + if ignore_self && ty.eq(&type_info, ty_engine) { continue; } - if is_type_info_storage_only(&ty) { + if ty_engine.is_type_info_storage_only(&ty) { errors.push(CompileError::InvalidStorageOnlyTypeDecl { - ty: ty.to_string(), + ty: ty_engine.help_out(ty).to_string(), span: span.clone(), }); } @@ -159,18 +169,18 @@ fn check_type(ty: TypeId, span: Span, ignore_self: bool) -> CompileResult<()> { ok((), warnings, errors) } -fn decl_validate(decl: &ty::TyDeclaration) -> CompileResult<()> { +fn decl_validate(ty_engine: &TypeEngine, decl: &ty::TyDeclaration) -> CompileResult<()> { let mut warnings: Vec = vec![]; let mut errors: Vec = vec![]; match decl { ty::TyDeclaration::VariableDeclaration(decl) => { check!( - check_type(decl.body.return_type, decl.name.span(), false), + check_type(ty_engine, decl.body.return_type, decl.name.span(), false), (), warnings, errors ); - check!(expr_validate(&decl.body), (), warnings, errors) + check!(expr_validate(ty_engine, &decl.body), (), warnings, errors) } ty::TyDeclaration::ConstantDeclaration(decl_id) => { let ty::TyConstantDeclaration { @@ -182,12 +192,12 @@ fn decl_validate(decl: &ty::TyDeclaration) -> CompileResult<()> { errors ); check!( - check_type(expr.return_type, name.span(), false), + check_type(ty_engine, expr.return_type, name.span(), false), (), warnings, errors ); - check!(expr_validate(&expr), (), warnings, errors) + check!(expr_validate(ty_engine, &expr), (), warnings, errors) } ty::TyDeclaration::FunctionDeclaration(decl_id) => { let ty::TyFunctionDeclaration { @@ -199,14 +209,14 @@ fn decl_validate(decl: &ty::TyDeclaration) -> CompileResult<()> { errors ); check!( - validate_decls_for_storage_only_types_in_codeblock(&body), + validate_decls_for_storage_only_types_in_codeblock(ty_engine, &body), (), warnings, errors ); for param in parameters { check!( - check_type(param.type_id, param.type_span.clone(), false), + check_type(ty_engine, param.type_id, param.type_span.clone(), false), continue, warnings, errors @@ -226,7 +236,7 @@ fn decl_validate(decl: &ty::TyDeclaration) -> CompileResult<()> { for method_id in methods { match de_get_function(method_id, &span) { Ok(method) => check!( - validate_decls_for_storage_only_types_in_codeblock(&method.body), + validate_decls_for_storage_only_types_in_codeblock(ty_engine, &method.body), continue, warnings, errors @@ -244,7 +254,7 @@ fn decl_validate(decl: &ty::TyDeclaration) -> CompileResult<()> { ); for field in fields { check!( - check_type(field.type_id, field.span.clone(), false), + check_type(ty_engine, field.type_id, field.span.clone(), false), continue, warnings, errors @@ -260,7 +270,7 @@ fn decl_validate(decl: &ty::TyDeclaration) -> CompileResult<()> { ); for variant in variants { check!( - check_type(variant.type_id, variant.span.clone(), false), + check_type(ty_engine, variant.type_id, variant.span.clone(), false), continue, warnings, errors @@ -276,7 +286,7 @@ fn decl_validate(decl: &ty::TyDeclaration) -> CompileResult<()> { ); for field in fields { check!( - check_type(field.type_id, field.name.span().clone(), true), + check_type(ty_engine, field.type_id, field.name.span().clone(), true), continue, warnings, errors @@ -290,18 +300,25 @@ fn decl_validate(decl: &ty::TyDeclaration) -> CompileResult<()> { } pub fn validate_decls_for_storage_only_types_in_ast( + ty_engine: &TypeEngine, ast_n: &ty::TyAstNodeContent, ) -> CompileResult<()> { - ast_node_validate(ast_n) + ast_node_validate(ty_engine, ast_n) } pub fn validate_decls_for_storage_only_types_in_codeblock( + ty_engine: &TypeEngine, cb: &ty::TyCodeBlock, ) -> CompileResult<()> { let mut warnings: Vec = vec![]; let mut errors: Vec = vec![]; for x in &cb.contents { - check!(ast_node_validate(&x.content), continue, warnings, errors) + check!( + ast_node_validate(ty_engine, &x.content), + continue, + warnings, + errors + ) } ok((), warnings, errors) } diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index b777febb314..821c7c75ab2 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -3,16 +3,15 @@ use crate::{ namespace::Path, semantic_analysis::{ast_node::Mode, Namespace}, type_system::{ - insert_type, monomorphize, unify_with_self, CopyTypes, EnforceTypeArguments, - MonomorphizeHelper, TypeArgument, TypeId, TypeInfo, + CopyTypes, EnforceTypeArguments, MonomorphizeHelper, TypeArgument, TypeId, TypeInfo, }, - CompileResult, CompileWarning, + CompileResult, CompileWarning, TypeEngine, }; use sway_error::error::CompileError; use sway_types::{span::Span, Ident}; /// Contextual state tracked and accumulated throughout type-checking. -pub struct TypeCheckContext<'ns> { +pub struct TypeCheckContext<'a> { /// The namespace context accumulated throughout type-checking. /// /// Internally, this includes: @@ -21,7 +20,7 @@ pub struct TypeCheckContext<'ns> { /// - The `init` module used to initialise submodule namespaces. /// - A `mod_path` that represents the current module being type-checked. This is automatically /// updated upon entering/exiting submodules via the `enter_submodule` method. - pub(crate) namespace: &'ns mut Namespace, + pub(crate) namespace: &'a mut Namespace, // The following set of fields are intentionally private. When a `TypeCheckContext` is passed // into a new node during type checking, these fields should be updated using the `with_*` @@ -47,9 +46,11 @@ pub struct TypeCheckContext<'ns> { /// Tracks the purity of the context, e.g. whether or not we should be allowed to write to /// storage. purity: Purity, + /// The type engine storing types. + pub(crate) type_engine: &'a TypeEngine, } -impl<'ns> TypeCheckContext<'ns> { +impl<'a> TypeCheckContext<'a> { /// Initialise a context at the top-level of a module with its namespace. /// /// Initializes with: @@ -58,17 +59,18 @@ impl<'ns> TypeCheckContext<'ns> { /// - mode: NoneAbi /// - help_text: "" /// - purity: Pure - pub fn from_root(root_namespace: &'ns mut Namespace) -> Self { - Self::from_module_namespace(root_namespace) + pub fn from_root(root_namespace: &'a mut Namespace, type_engine: &'a TypeEngine) -> Self { + Self::from_module_namespace(root_namespace, type_engine) } - fn from_module_namespace(namespace: &'ns mut Namespace) -> Self { + fn from_module_namespace(namespace: &'a mut Namespace, type_engine: &'a TypeEngine) -> Self { Self { namespace, - type_annotation: insert_type(TypeInfo::Unknown), + type_engine, + type_annotation: type_engine.insert_type(TypeInfo::Unknown), help_text: "", // TODO: Contract? Should this be passed in based on program kind (aka TreeType)? - self_type: insert_type(TypeInfo::Contract), + self_type: type_engine.insert_type(TypeInfo::Contract), mode: Mode::NonAbi, purity: Purity::default(), } @@ -82,7 +84,7 @@ impl<'ns> TypeCheckContext<'ns> { /// rather than the original namespace reference, we instead restrict the returned context to /// the local scope and avoid consuming the original context when providing context to the /// first visited child node. - pub fn by_ref(&mut self) -> TypeCheckContext { + pub fn by_ref(&mut self) -> TypeCheckContext<'_> { TypeCheckContext { namespace: self.namespace, type_annotation: self.type_annotation, @@ -90,11 +92,12 @@ impl<'ns> TypeCheckContext<'ns> { mode: self.mode, help_text: self.help_text, purity: self.purity, + type_engine: self.type_engine, } } /// Scope the `TypeCheckContext` with the given `Namespace`. - pub fn scoped(self, namespace: &mut Namespace) -> TypeCheckContext { + pub fn scoped(self, namespace: &'a mut Namespace) -> TypeCheckContext<'a> { TypeCheckContext { namespace, type_annotation: self.type_annotation, @@ -102,6 +105,7 @@ impl<'ns> TypeCheckContext<'ns> { mode: self.mode, help_text: self.help_text, purity: self.purity, + type_engine: self.type_engine, } } @@ -109,16 +113,17 @@ impl<'ns> TypeCheckContext<'ns> { /// type-checking its content. /// /// Returns the result of the given `with_submod_ctx` function. - pub fn enter_submodule(self, dep_name: Ident, with_submod_ctx: F) -> T - where - F: FnOnce(TypeCheckContext) -> T, - { + pub fn enter_submodule( + self, + dep_name: Ident, + with_submod_ctx: impl FnOnce(TypeCheckContext) -> T, + ) -> T { // We're checking a submodule, so no need to pass through anything other than the // namespace. However, we will likely want to pass through the type engine and declaration // engine here once they're added. let Self { namespace, .. } = self; let mut submod_ns = namespace.enter_submodule(dep_name); - let submod_ctx = TypeCheckContext::from_module_namespace(&mut submod_ns); + let submod_ctx = TypeCheckContext::from_module_namespace(&mut submod_ns, self.type_engine); with_submod_ctx(submod_ctx) } @@ -187,7 +192,7 @@ impl<'ns> TypeCheckContext<'ns> { T: MonomorphizeHelper + CopyTypes, { let mod_path = self.namespace.mod_path.clone(); - monomorphize( + self.type_engine.monomorphize( value, type_arguments, enforce_type_arguments, @@ -207,6 +212,7 @@ impl<'ns> TypeCheckContext<'ns> { type_info_prefix: Option<&Path>, ) -> CompileResult { self.namespace.resolve_type_with_self( + self.type_engine, type_id, self.self_type, span, @@ -223,7 +229,7 @@ impl<'ns> TypeCheckContext<'ns> { type_info_prefix: Option<&Path>, ) -> CompileResult { self.namespace - .resolve_type_without_self(type_id, span, type_info_prefix) + .resolve_type_without_self(self.type_engine, type_id, span, type_info_prefix) } /// Short-hand around `type_system::unify_with_self`, where the `TypeCheckContext` provides the @@ -233,7 +239,7 @@ impl<'ns> TypeCheckContext<'ns> { ty: TypeId, span: &Span, ) -> (Vec, Vec) { - unify_with_self( + self.type_engine.unify_with_self( ty, self.type_annotation(), self.self_type(), diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index c27f80ea5e2..218a753e4e5 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -44,20 +44,27 @@ use std::{ pub fn convert_parse_tree( handler: &Handler, + type_engine: &TypeEngine, module: Module, ) -> Result<(TreeType, ParseTree), ErrorEmitted> { - let tree_type = match module.kind { + let tree_type = convert_module_kind(&module.kind); + let tree = module_to_sway_parse_tree(handler, type_engine, module)?; + Ok((tree_type, tree)) +} + +/// Converts the module kind of the AST to the tree type of the parsed tree. +pub fn convert_module_kind(kind: &ModuleKind) -> TreeType { + match kind { ModuleKind::Script { .. } => TreeType::Script, ModuleKind::Contract { .. } => TreeType::Contract, ModuleKind::Predicate { .. } => TreeType::Predicate, - ModuleKind::Library { ref name, .. } => TreeType::Library { name: name.clone() }, - }; - let tree = module_to_sway_parse_tree(handler, module)?; - Ok((tree_type, tree)) + ModuleKind::Library { name, .. } => TreeType::Library { name: name.clone() }, + } } pub fn module_to_sway_parse_tree( handler: &Handler, + type_engine: &TypeEngine, module: Module, ) -> Result { let span = module.span(); @@ -65,7 +72,7 @@ pub fn module_to_sway_parse_tree( let mut root_nodes: Vec = vec![]; let mut prev_item: Option> = None; for item in module.items { - let ast_nodes = item_to_ast_nodes(handler, item.clone(), true, prev_item)?; + let ast_nodes = item_to_ast_nodes(handler, type_engine, item.clone(), true, prev_item)?; root_nodes.extend(ast_nodes); prev_item = Some(item); } @@ -85,6 +92,7 @@ fn ast_node_is_test_fn(node: &AstNode) -> bool { fn item_to_ast_nodes( handler: &Handler, + type_engine: &TypeEngine, item: Item, is_root: bool, prev_item: Option>, @@ -145,14 +153,14 @@ fn item_to_ast_nodes( .map(AstNodeContent::UseStatement) .collect(), ItemKind::Struct(item_struct) => decl(Declaration::StructDeclaration( - item_struct_to_struct_declaration(handler, item_struct, attributes)?, + item_struct_to_struct_declaration(handler, type_engine, item_struct, attributes)?, )), ItemKind::Enum(item_enum) => decl(Declaration::EnumDeclaration( - item_enum_to_enum_declaration(handler, item_enum, attributes)?, + item_enum_to_enum_declaration(handler, type_engine, item_enum, attributes)?, )), ItemKind::Fn(item_fn) => { let function_declaration = - item_fn_to_function_declaration(handler, item_fn, attributes)?; + item_fn_to_function_declaration(handler, type_engine, item_fn, attributes)?; for param in &function_declaration.parameters { if matches!(param.type_info, TypeInfo::SelfType) { let error = ConvertParseTreeError::SelfParameterNotAllowedForFreeFn { @@ -164,17 +172,22 @@ fn item_to_ast_nodes( decl(Declaration::FunctionDeclaration(function_declaration)) } ItemKind::Trait(item_trait) => decl(Declaration::TraitDeclaration( - item_trait_to_trait_declaration(handler, item_trait, attributes)?, + item_trait_to_trait_declaration(handler, type_engine, item_trait, attributes)?, )), - ItemKind::Impl(item_impl) => decl(item_impl_to_declaration(handler, item_impl)?), + ItemKind::Impl(item_impl) => { + decl(item_impl_to_declaration(handler, type_engine, item_impl)?) + } ItemKind::Abi(item_abi) => decl(Declaration::AbiDeclaration(item_abi_to_abi_declaration( - handler, item_abi, attributes, + handler, + type_engine, + item_abi, + attributes, )?)), ItemKind::Const(item_const) => decl(Declaration::ConstantDeclaration( - item_const_to_constant_declaration(handler, item_const, attributes)?, + item_const_to_constant_declaration(handler, type_engine, item_const, attributes)?, )), ItemKind::Storage(item_storage) => decl(Declaration::StorageDeclaration( - item_storage_to_storage_declaration(handler, item_storage, attributes)?, + item_storage_to_storage_declaration(handler, type_engine, item_storage, attributes)?, )), }; @@ -271,6 +284,7 @@ fn emit_all(handler: &Handler, errors: Vec) -> Option Result { @@ -283,7 +297,7 @@ fn item_struct_to_struct_declaration( .into_iter() .map(|type_field| { let attributes = item_attrs_to_map(handler, &type_field.attribute_list)?; - type_field_to_struct_field(handler, type_field.value, attributes) + type_field_to_struct_field(handler, type_engine, type_field.value, attributes) }) .collect::, _>>()?; @@ -314,6 +328,7 @@ fn item_struct_to_struct_declaration( fields, type_parameters: generic_params_opt_to_type_parameters( handler, + type_engine, item_struct.generics, item_struct.where_clause_opt, )?, @@ -325,6 +340,7 @@ fn item_struct_to_struct_declaration( fn item_enum_to_enum_declaration( handler: &Handler, + type_engine: &TypeEngine, item_enum: ItemEnum, attributes: AttributesMap, ) -> Result { @@ -337,7 +353,7 @@ fn item_enum_to_enum_declaration( .enumerate() .map(|(tag, type_field)| { let attributes = item_attrs_to_map(handler, &type_field.attribute_list)?; - type_field_to_enum_variant(handler, type_field.value, attributes, tag) + type_field_to_enum_variant(handler, type_engine, type_field.value, attributes, tag) }) .collect::, _>>()?; @@ -366,6 +382,7 @@ fn item_enum_to_enum_declaration( name: item_enum.name, type_parameters: generic_params_opt_to_type_parameters( handler, + type_engine, item_enum.generics, item_enum.where_clause_opt, )?, @@ -379,6 +396,7 @@ fn item_enum_to_enum_declaration( fn item_fn_to_function_declaration( handler: &Handler, + type_engine: &TypeEngine, item_fn: ItemFn, attributes: AttributesMap, ) -> Result { @@ -392,18 +410,20 @@ fn item_fn_to_function_declaration( attributes, name: item_fn.fn_signature.name, visibility: pub_token_opt_to_visibility(item_fn.fn_signature.visibility), - body: braced_code_block_contents_to_code_block(handler, item_fn.body)?, + body: braced_code_block_contents_to_code_block(handler, type_engine, item_fn.body)?, parameters: fn_args_to_function_parameters( handler, + type_engine, item_fn.fn_signature.arguments.into_inner(), )?, span, return_type: match item_fn.fn_signature.return_type_opt { - Some((_right_arrow, ty)) => ty_to_type_info(handler, ty)?, + Some((_right_arrow, ty)) => ty_to_type_info(handler, type_engine, ty)?, None => TypeInfo::Tuple(Vec::new()), }, type_parameters: generic_params_opt_to_type_parameters( handler, + type_engine, item_fn.fn_signature.generics, item_fn.fn_signature.where_clause_opt, )?, @@ -446,12 +466,14 @@ fn get_attributed_purity( fn item_trait_to_trait_declaration( handler: &Handler, + type_engine: &TypeEngine, item_trait: ItemTrait, attributes: AttributesMap, ) -> Result { let span = item_trait.span(); let type_parameters = generic_params_opt_to_type_parameters( handler, + type_engine, item_trait.generics, item_trait.where_clause_opt, )?; @@ -462,7 +484,7 @@ fn item_trait_to_trait_declaration( .into_iter() .map(|(fn_signature, _)| { let attributes = item_attrs_to_map(handler, &fn_signature.attribute_list)?; - fn_signature_to_trait_fn(handler, fn_signature.value, attributes) + fn_signature_to_trait_fn(handler, type_engine, fn_signature.value, attributes) }) .collect::>()? }; @@ -473,7 +495,7 @@ fn item_trait_to_trait_declaration( .into_iter() .map(|item_fn| { let attributes = item_attrs_to_map(handler, &item_fn.attribute_list)?; - item_fn_to_function_declaration(handler, item_fn.value, attributes) + item_fn_to_function_declaration(handler, type_engine, item_fn.value, attributes) }) .collect::>()?, }; @@ -496,23 +518,25 @@ fn item_trait_to_trait_declaration( fn item_impl_to_declaration( handler: &Handler, + type_engine: &TypeEngine, item_impl: ItemImpl, ) -> Result { let block_span = item_impl.span(); let type_implementing_for_span = item_impl.ty.span(); - let type_implementing_for = ty_to_type_info(handler, item_impl.ty)?; + let type_implementing_for = ty_to_type_info(handler, type_engine, item_impl.ty)?; let functions = item_impl .contents .into_inner() .into_iter() .map(|item| { let attributes = item_attrs_to_map(handler, &item.attribute_list)?; - item_fn_to_function_declaration(handler, item.value, attributes) + item_fn_to_function_declaration(handler, type_engine, item.value, attributes) }) .collect::>()?; let impl_type_parameters = generic_params_opt_to_type_parameters( handler, + type_engine, item_impl.generic_params_opt, item_impl.where_clause_opt, )?; @@ -520,7 +544,7 @@ fn item_impl_to_declaration( match item_impl.trait_opt { Some((path_type, _)) => { let (trait_name, trait_type_arguments) = - path_type_to_call_path_and_type_arguments(handler, path_type)?; + path_type_to_call_path_and_type_arguments(handler, type_engine, path_type)?; let impl_trait = ImplTrait { impl_type_parameters, trait_name, @@ -551,6 +575,7 @@ fn item_impl_to_declaration( fn path_type_to_call_path_and_type_arguments( handler: &Handler, + type_engine: &TypeEngine, PathType { root_opt, prefix, @@ -577,7 +602,9 @@ fn path_type_to_call_path_and_type_arguments( }; let ty_args = match suffix.generics_opt { - Some((_, generic_args)) => generic_args_to_type_arguments(handler, generic_args)?, + Some((_, generic_args)) => { + generic_args_to_type_arguments(handler, type_engine, generic_args)? + } None => vec![], }; @@ -586,6 +613,7 @@ fn path_type_to_call_path_and_type_arguments( fn item_abi_to_abi_declaration( handler: &Handler, + type_engine: &TypeEngine, item_abi: ItemAbi, attributes: AttributesMap, ) -> Result { @@ -599,7 +627,7 @@ fn item_abi_to_abi_declaration( .into_iter() .map(|(fn_signature, _semicolon_token)| { let attributes = item_attrs_to_map(handler, &fn_signature.attribute_list)?; - fn_signature_to_trait_fn(handler, fn_signature.value, attributes) + fn_signature_to_trait_fn(handler, type_engine, fn_signature.value, attributes) }) .collect::>()? }, @@ -610,7 +638,7 @@ fn item_abi_to_abi_declaration( .into_iter() .map(|item_fn| { let attributes = item_attrs_to_map(handler, &item_fn.attribute_list)?; - item_fn_to_function_declaration(handler, item_fn.value, attributes) + item_fn_to_function_declaration(handler, type_engine, item_fn.value, attributes) }) .collect::>()?, }, @@ -621,13 +649,14 @@ fn item_abi_to_abi_declaration( pub(crate) fn item_const_to_constant_declaration( handler: &Handler, + type_engine: &TypeEngine, item_const: ItemConst, attributes: AttributesMap, ) -> Result { let span = item_const.span(); let (type_ascription, type_ascription_span) = match item_const.ty_opt { Some((_colon_token, ty)) => { - let type_ascription = ty_to_type_info(handler, ty.clone())?; + let type_ascription = ty_to_type_info(handler, type_engine, ty.clone())?; let type_ascription_span = if let Ty::Path(path_type) = &ty { path_type.prefix.name.span() } else { @@ -642,7 +671,7 @@ pub(crate) fn item_const_to_constant_declaration( name: item_const.name, type_ascription, type_ascription_span, - value: expr_to_expression(handler, item_const.expr)?, + value: expr_to_expression(handler, type_engine, item_const.expr)?, visibility: pub_token_opt_to_visibility(item_const.visibility), attributes, span, @@ -651,6 +680,7 @@ pub(crate) fn item_const_to_constant_declaration( fn item_storage_to_storage_declaration( handler: &Handler, + type_engine: &TypeEngine, item_storage: ItemStorage, attributes: AttributesMap, ) -> Result { @@ -662,7 +692,7 @@ fn item_storage_to_storage_declaration( .into_iter() .map(|storage_field| { let attributes = item_attrs_to_map(handler, &storage_field.attribute_list)?; - storage_field_to_storage_field(handler, storage_field.value, attributes) + storage_field_to_storage_field(handler, type_engine, storage_field.value, attributes) }) .collect::>()?; @@ -691,6 +721,7 @@ fn item_storage_to_storage_declaration( fn type_field_to_struct_field( handler: &Handler, + type_engine: &TypeEngine, type_field: TypeField, attributes: AttributesMap, ) -> Result { @@ -699,7 +730,7 @@ fn type_field_to_struct_field( let struct_field = StructField { name: type_field.name, attributes, - type_info: ty_to_type_info(handler, type_field.ty)?, + type_info: ty_to_type_info(handler, type_engine, type_field.ty)?, span, type_span, }; @@ -708,6 +739,7 @@ fn type_field_to_struct_field( fn generic_params_opt_to_type_parameters( handler: &Handler, + type_engine: &TypeEngine, generic_params_opt: Option, where_clause_opt: Option, ) -> Result, ErrorEmitted> { @@ -726,7 +758,7 @@ fn generic_params_opt_to_type_parameters( .into_inner() .into_iter() .map(|ident| { - let custom_type = insert_type(TypeInfo::Custom { + let custom_type = type_engine.insert_type(TypeInfo::Custom { name: ident.clone(), type_arguments: None, }); @@ -761,12 +793,12 @@ fn generic_params_opt_to_type_parameters( param_to_edit.trait_constraints_span = Span::join(ty_name.span(), bounds.span()); param_to_edit.trait_constraints.extend( - traits_to_call_paths(handler, bounds)?.into_iter().map( - |(trait_name, type_arguments)| TraitConstraint { + traits_to_call_paths(handler, type_engine, bounds)? + .into_iter() + .map(|(trait_name, type_arguments)| TraitConstraint { trait_name, type_arguments, - }, - ), + }), ); } if let Some(errors) = emit_all(handler, errors) { @@ -785,6 +817,7 @@ fn pub_token_opt_to_visibility(pub_token_opt: Option) -> Visibility { fn type_field_to_enum_variant( handler: &Handler, + type_engine: &TypeEngine, type_field: TypeField, attributes: AttributesMap, tag: usize, @@ -799,7 +832,7 @@ fn type_field_to_enum_variant( let enum_variant = EnumVariant { name: type_field.name, attributes, - type_info: ty_to_type_info(handler, type_field.ty)?, + type_info: ty_to_type_info(handler, type_engine, type_field.ty)?, type_span, tag, span, @@ -809,6 +842,7 @@ fn type_field_to_enum_variant( fn braced_code_block_contents_to_code_block( handler: &Handler, + type_engine: &TypeEngine, braced_code_block_contents: Braces, ) -> Result { let whole_block_span = braced_code_block_contents.span(); @@ -816,11 +850,11 @@ fn braced_code_block_contents_to_code_block( let contents = { let mut contents = Vec::new(); for statement in code_block_contents.statements { - let ast_nodes = statement_to_ast_nodes(handler, statement)?; + let ast_nodes = statement_to_ast_nodes(handler, type_engine, statement)?; contents.extend(ast_nodes); } if let Some(expr) = code_block_contents.final_expr_opt { - let final_ast_node = expr_to_ast_node(handler, *expr, false)?; + let final_ast_node = expr_to_ast_node(handler, type_engine, *expr, false)?; contents.push(final_ast_node); } contents @@ -833,12 +867,13 @@ fn braced_code_block_contents_to_code_block( fn fn_args_to_function_parameters( handler: &Handler, + type_engine: &TypeEngine, fn_args: FnArgs, ) -> Result, ErrorEmitted> { let function_parameters = match fn_args { FnArgs::Static(args) => args .into_iter() - .map(|fn_arg| fn_arg_to_function_parameter(handler, fn_arg)) + .map(|fn_arg| fn_arg_to_function_parameter(handler, type_engine, fn_arg)) .collect::>()?, FnArgs::NonStatic { self_token, @@ -862,7 +897,8 @@ fn fn_args_to_function_parameters( }]; if let Some((_comma_token, args)) = args_opt { for arg in args { - let function_parameter = fn_arg_to_function_parameter(handler, arg)?; + let function_parameter = + fn_arg_to_function_parameter(handler, type_engine, arg)?; function_parameters.push(function_parameter); } } @@ -902,18 +938,27 @@ pub(crate) fn type_name_to_type_info_opt(name: &Ident) -> Option { } } -fn ty_to_type_info(handler: &Handler, ty: Ty) -> Result { +fn ty_to_type_info( + handler: &Handler, + type_engine: &TypeEngine, + ty: Ty, +) -> Result { let type_info = match ty { - Ty::Path(path_type) => path_type_to_type_info(handler, path_type)?, + Ty::Path(path_type) => path_type_to_type_info(handler, type_engine, path_type)?, Ty::Tuple(parenthesized_ty_tuple_descriptor) => { TypeInfo::Tuple(ty_tuple_descriptor_to_type_arguments( handler, + type_engine, parenthesized_ty_tuple_descriptor.into_inner(), )?) } Ty::Array(bracketed_ty_array_descriptor) => { let ty_array_descriptor = bracketed_ty_array_descriptor.into_inner(); - let initial_elem_ty = insert_type(ty_to_type_info(handler, *ty_array_descriptor.ty)?); + let initial_elem_ty = type_engine.insert_type(ty_to_type_info( + handler, + type_engine, + *ty_array_descriptor.ty, + )?); TypeInfo::Array( initial_elem_ty, expr_to_usize(handler, *ty_array_descriptor.length)?, @@ -926,9 +971,13 @@ fn ty_to_type_info(handler: &Handler, ty: Ty) -> Result Ok(type_info) } -fn ty_to_type_argument(handler: &Handler, ty: Ty) -> Result { +fn ty_to_type_argument( + handler: &Handler, + type_engine: &TypeEngine, + ty: Ty, +) -> Result { let span = ty.span(); - let initial_type_id = insert_type(ty_to_type_info(handler, ty)?); + let initial_type_id = type_engine.insert_type(ty_to_type_info(handler, type_engine, ty)?); let type_argument = TypeArgument { type_id: initial_type_id, initial_type_id, @@ -939,6 +988,7 @@ fn ty_to_type_argument(handler: &Handler, ty: Ty) -> Result Result { @@ -950,9 +1000,13 @@ fn fn_signature_to_trait_fn( name: fn_signature.name, purity: get_attributed_purity(handler, &attributes)?, attributes, - parameters: fn_args_to_function_parameters(handler, fn_signature.arguments.into_inner())?, + parameters: fn_args_to_function_parameters( + handler, + type_engine, + fn_signature.arguments.into_inner(), + )?, return_type: match fn_signature.return_type_opt { - Some((_right_arrow_token, ty)) => ty_to_type_info(handler, ty)?, + Some((_right_arrow_token, ty)) => ty_to_type_info(handler, type_engine, ty)?, None => TypeInfo::Tuple(Vec::new()), }, return_type_span, @@ -962,14 +1016,16 @@ fn fn_signature_to_trait_fn( fn traits_to_call_paths( handler: &Handler, + type_engine: &TypeEngine, traits: Traits, ) -> Result)>, ErrorEmitted> { let mut parsed_traits = vec![path_type_to_call_path_and_type_arguments( handler, + type_engine, traits.prefix, )?]; for (_add_token, suffix) in traits.suffixes { - let supertrait = path_type_to_call_path_and_type_arguments(handler, suffix)?; + let supertrait = path_type_to_call_path_and_type_arguments(handler, type_engine, suffix)?; parsed_traits.push(supertrait); } Ok(parsed_traits) @@ -1021,12 +1077,13 @@ fn path_type_to_call_path( fn expr_to_ast_node( handler: &Handler, + type_engine: &TypeEngine, expr: Expr, is_statement: bool, ) -> Result { let span = expr.span(); let ast_node = { - let expression = expr_to_expression(handler, expr)?; + let expression = expr_to_expression(handler, type_engine, expr)?; if !is_statement { AstNode { content: AstNodeContent::ImplicitReturnExpression(expression), @@ -1044,26 +1101,32 @@ fn expr_to_ast_node( fn abi_cast_args_to_abi_cast_expression( handler: &Handler, + type_engine: &TypeEngine, args: Parens, ) -> Result, ErrorEmitted> { let AbiCastArgs { name, address, .. } = args.into_inner(); let abi_name = path_type_to_call_path(handler, name)?; - let address = Box::new(expr_to_expression(handler, *address)?); + let address = Box::new(expr_to_expression(handler, type_engine, *address)?); Ok(Box::new(AbiCastExpression { abi_name, address })) } fn struct_path_and_fields_to_struct_expression( handler: &Handler, + type_engine: &TypeEngine, path: PathExpr, fields: Braces>, ) -> Result, ErrorEmitted> { - let call_path_binding = path_expr_to_call_path_binding(handler, path)?; + let call_path_binding = path_expr_to_call_path_binding(handler, type_engine, path)?; let fields = { fields .into_inner() .into_iter() .map(|expr_struct_field| { - expr_struct_field_to_struct_expression_field(handler, expr_struct_field) + expr_struct_field_to_struct_expression_field( + handler, + type_engine, + expr_struct_field, + ) }) .collect::>()? }; @@ -1075,13 +1138,14 @@ fn struct_path_and_fields_to_struct_expression( fn method_call_fields_to_method_application_expression( handler: &Handler, + type_engine: &TypeEngine, target: Box, path_seg: PathExprSegment, contract_args_opt: Option>>, args: Parens>, ) -> Result, ErrorEmitted> { let (method_name, type_arguments) = - path_expr_segment_to_ident_or_type_argument(handler, path_seg)?; + path_expr_segment_to_ident_or_type_argument(handler, type_engine, path_seg)?; let span = match &*type_arguments { [] => method_name.span(), @@ -1099,13 +1163,17 @@ fn method_call_fields_to_method_application_expression( .into_inner() .into_iter() .map(|expr_struct_field| { - expr_struct_field_to_struct_expression_field(handler, expr_struct_field) + expr_struct_field_to_struct_expression_field( + handler, + type_engine, + expr_struct_field, + ) }) .collect::>()?, }; let arguments = iter::once(*target) .chain(args.into_inner().into_iter()) - .map(|expr| expr_to_expression(handler, expr)) + .map(|expr| expr_to_expression(handler, type_engine, expr)) .collect::>()?; Ok(Box::new(MethodApplicationExpression { method_name_binding, @@ -1116,6 +1184,7 @@ fn method_call_fields_to_method_application_expression( fn expr_func_app_to_expression_kind( handler: &Handler, + type_engine: &TypeEngine, func: Box, args: Parens>, ) -> Result { @@ -1140,7 +1209,7 @@ fn expr_func_app_to_expression_kind( Ok(match generics_opt { Some((_, generic_args)) => { let span = generic_args.span(); - let ty_args = generic_args_to_type_arguments(handler, generic_args)?; + let ty_args = generic_args_to_type_arguments(handler, type_engine, generic_args)?; (ty_args, Some(span)) } None => <_>::default(), @@ -1164,7 +1233,7 @@ fn expr_func_app_to_expression_kind( let arguments = args .into_inner() .into_iter() - .map(|expr| expr_to_expression(handler, expr)) + .map(|expr| expr_to_expression(handler, type_engine, expr)) .collect::>()?; let name_args_span = |start, end: Option<_>| match end { @@ -1248,7 +1317,11 @@ fn expr_func_app_to_expression_kind( ))) } -fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { +fn expr_to_expression( + handler: &Handler, + type_engine: &TypeEngine, + expr: Expr, +) -> Result { let span = expr.span(); let expression = match expr { Expr::Error(part_spans) => Expression { @@ -1261,7 +1334,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let abi_cast_expression = abi_cast_args_to_abi_cast_expression(handler, args)?; + let abi_cast_expression = + abi_cast_args_to_abi_cast_expression(handler, type_engine, args)?; Expression { kind: ExpressionKind::AbiCast(abi_cast_expression), span, @@ -1269,7 +1343,7 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { let struct_expression = - struct_path_and_fields_to_struct_expression(handler, path, fields)?; + struct_path_and_fields_to_struct_expression(handler, type_engine, path, fields)?; Expression { kind: ExpressionKind::Struct(struct_expression), span, @@ -1278,6 +1352,7 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { let fields = expr_tuple_descriptor_to_expressions( handler, + type_engine, parenthesized_expr_tuple_descriptor.into_inner(), )?; Expression { @@ -1285,16 +1360,18 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result expr_to_expression(handler, *parens.into_inner())?, - Expr::Block(braced_code_block_contents) => { - braced_code_block_contents_to_expression(handler, braced_code_block_contents)? - } + Expr::Parens(parens) => expr_to_expression(handler, type_engine, *parens.into_inner())?, + Expr::Block(braced_code_block_contents) => braced_code_block_contents_to_expression( + handler, + type_engine, + braced_code_block_contents, + )?, Expr::Array(bracketed_expr_array_descriptor) => { match bracketed_expr_array_descriptor.into_inner() { ExprArrayDescriptor::Sequence(exprs) => { let contents = exprs .into_iter() - .map(|expr| expr_to_expression(handler, expr)) + .map(|expr| expr_to_expression(handler, type_engine, expr)) .collect::>()?; Expression { kind: ExpressionKind::Array(contents), @@ -1302,7 +1379,7 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let expression = expr_to_expression(handler, *value)?; + let expression = expr_to_expression(handler, type_engine, *value)?; let length = expr_to_usize(handler, *length)?; let contents = iter::repeat_with(|| expression.clone()) .take(length) @@ -1315,7 +1392,7 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let asm_expression = asm_block_to_asm_expression(handler, asm_block)?; + let asm_expression = asm_block_to_asm_expression(handler, type_engine, asm_block)?; Expression { kind: ExpressionKind::Asm(asm_expression), span, @@ -1323,7 +1400,7 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { let expression = match expr_opt { - Some(expr) => expr_to_expression(handler, *expr)?, + Some(expr) => expr_to_expression(handler, type_engine, *expr)?, None => Expression { kind: ExpressionKind::Tuple(Vec::new()), span: span.clone(), @@ -1334,11 +1411,11 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result if_expr_to_expression(handler, if_expr)?, + Expr::If(if_expr) => if_expr_to_expression(handler, type_engine, if_expr)?, Expr::Match { value, branches, .. } => { - let value = expr_to_expression(handler, *value)?; + let value = expr_to_expression(handler, type_engine, *value)?; let var_decl_span = value.span(); // Generate a deterministic name for the variable returned by the match expression. @@ -1363,7 +1440,9 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result>()? }; Expression { @@ -1401,19 +1480,19 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result Expression { kind: ExpressionKind::WhileLoop(WhileLoopExpression { - condition: Box::new(expr_to_expression(handler, *condition)?), - body: braced_code_block_contents_to_code_block(handler, block)?, + condition: Box::new(expr_to_expression(handler, type_engine, *condition)?), + body: braced_code_block_contents_to_code_block(handler, type_engine, block)?, }), span, }, Expr::FuncApp { func, args } => { - let kind = expr_func_app_to_expression_kind(handler, func, args)?; + let kind = expr_func_app_to_expression_kind(handler, type_engine, func, args)?; Expression { kind, span } } Expr::Index { target, arg } => Expression { kind: ExpressionKind::ArrayIndex(ArrayIndexExpression { - prefix: Box::new(expr_to_expression(handler, *target)?), - index: Box::new(expr_to_expression(handler, *arg.into_inner())?), + prefix: Box::new(expr_to_expression(handler, type_engine, *target)?), + index: Box::new(expr_to_expression(handler, type_engine, *arg.into_inner())?), }), span, }, @@ -1427,6 +1506,7 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result Result ExpressionKind::Subfield(SubfieldExpression { - prefix: Box::new(expr_to_expression(handler, *target)?), + prefix: Box::new(expr_to_expression(handler, type_engine, *target)?), field_to_access: name, }), }; @@ -1481,7 +1561,7 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result Expression { kind: ExpressionKind::TupleIndex(TupleIndexExpression { - prefix: Box::new(expr_to_expression(handler, *target)?), + prefix: Box::new(expr_to_expression(handler, type_engine, *target)?), index: match usize::try_from(field) { Ok(index) => index, Err(..) => { @@ -1497,7 +1577,7 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result unimplemented!(), Expr::Deref { .. } => unimplemented!(), Expr::Not { bang_token, expr } => { - let expr = expr_to_expression(handler, *expr)?; + let expr = expr_to_expression(handler, type_engine, *expr)?; op_call("not", bang_token.span(), span, &[expr])? } Expr::Pow { @@ -1505,8 +1585,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("pow", double_star_token.span(), span, &vec![lhs, rhs])? } Expr::Mul { @@ -1514,8 +1594,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("multiply", star_token.span(), span, &vec![lhs, rhs])? } Expr::Div { @@ -1523,8 +1603,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("divide", forward_slash_token.span(), span, &vec![lhs, rhs])? } Expr::Modulo { @@ -1532,8 +1612,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("modulo", percent_token.span(), span, &vec![lhs, rhs])? } Expr::Add { @@ -1541,8 +1621,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("add", add_token.span(), span, &vec![lhs, rhs])? } Expr::Sub { @@ -1550,8 +1630,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("subtract", sub_token.span(), span, &vec![lhs, rhs])? } Expr::Shl { @@ -1559,8 +1639,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("lsh", shl_token.span(), span, &vec![lhs, rhs])? } Expr::Shr { @@ -1568,8 +1648,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("rsh", shr_token.span(), span, &vec![lhs, rhs])? } Expr::BitAnd { @@ -1577,8 +1657,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("binary_and", ampersand_token.span(), span, &vec![lhs, rhs])? } Expr::BitXor { @@ -1586,8 +1666,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("binary_xor", caret_token.span(), span, &vec![lhs, rhs])? } Expr::BitOr { @@ -1595,8 +1675,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("binary_or", pipe_token.span(), span, &vec![lhs, rhs])? } Expr::Equal { @@ -1604,8 +1684,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("eq", double_eq_token.span(), span, &vec![lhs, rhs])? } Expr::NotEqual { @@ -1613,8 +1693,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("neq", bang_eq_token.span(), span, &vec![lhs, rhs])? } Expr::LessThan { @@ -1622,8 +1702,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("lt", less_than_token.span(), span, &vec![lhs, rhs])? } Expr::GreaterThan { @@ -1631,8 +1711,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("gt", greater_than_token.span(), span, &vec![lhs, rhs])? } Expr::LessThanEq { @@ -1640,8 +1720,8 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("le", less_than_eq_token.span(), span, &vec![lhs, rhs])? } Expr::GreaterThanEq { @@ -1649,23 +1729,23 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result { - let lhs = expr_to_expression(handler, *lhs)?; - let rhs = expr_to_expression(handler, *rhs)?; + let lhs = expr_to_expression(handler, type_engine, *lhs)?; + let rhs = expr_to_expression(handler, type_engine, *rhs)?; op_call("ge", greater_than_eq_token.span(), span, &vec![lhs, rhs])? } Expr::LogicalAnd { lhs, rhs, .. } => Expression { kind: ExpressionKind::LazyOperator(LazyOperatorExpression { op: LazyOp::And, - lhs: Box::new(expr_to_expression(handler, *lhs)?), - rhs: Box::new(expr_to_expression(handler, *rhs)?), + lhs: Box::new(expr_to_expression(handler, type_engine, *lhs)?), + rhs: Box::new(expr_to_expression(handler, type_engine, *rhs)?), }), span, }, Expr::LogicalOr { lhs, rhs, .. } => Expression { kind: ExpressionKind::LazyOperator(LazyOperatorExpression { op: LazyOp::Or, - lhs: Box::new(expr_to_expression(handler, *lhs)?), - rhs: Box::new(expr_to_expression(handler, *rhs)?), + lhs: Box::new(expr_to_expression(handler, type_engine, *lhs)?), + rhs: Box::new(expr_to_expression(handler, type_engine, *rhs)?), }), span, }, @@ -1680,20 +1760,21 @@ fn expr_to_expression(handler: &Handler, expr: Expr) -> Result match op_variant { ReassignmentOpVariant::Equals => Expression { kind: ExpressionKind::Reassignment(ReassignmentExpression { - lhs: assignable_to_reassignment_target(handler, assignable)?, - rhs: Box::new(expr_to_expression(handler, *expr)?), + lhs: assignable_to_reassignment_target(handler, type_engine, assignable)?, + rhs: Box::new(expr_to_expression(handler, type_engine, *expr)?), }), span, }, op_variant => { - let lhs = assignable_to_reassignment_target(handler, assignable.clone())?; + let lhs = + assignable_to_reassignment_target(handler, type_engine, assignable.clone())?; let rhs = Box::new(op_call( op_variant.core_name(), op_span, span.clone(), &vec![ - assignable_to_expression(handler, assignable)?, - expr_to_expression(handler, *expr)?, + assignable_to_expression(handler, type_engine, assignable)?, + expr_to_expression(handler, type_engine, *expr)?, ], )?); Expression { @@ -1746,6 +1827,7 @@ fn op_call( fn storage_field_to_storage_field( handler: &Handler, + type_engine: &TypeEngine, storage_field: sway_ast::StorageField, attributes: AttributesMap, ) -> Result { @@ -1757,21 +1839,24 @@ fn storage_field_to_storage_field( let storage_field = StorageField { attributes, name: storage_field.name, - type_info: ty_to_type_info(handler, storage_field.ty)?, + type_info: ty_to_type_info(handler, type_engine, storage_field.ty)?, type_info_span, - initializer: expr_to_expression(handler, storage_field.initializer)?, + initializer: expr_to_expression(handler, type_engine, storage_field.initializer)?, }; Ok(storage_field) } fn statement_to_ast_nodes( handler: &Handler, + type_engine: &TypeEngine, statement: Statement, ) -> Result, ErrorEmitted> { let ast_nodes = match statement { - Statement::Let(statement_let) => statement_let_to_ast_nodes(handler, statement_let)?, + Statement::Let(statement_let) => { + statement_let_to_ast_nodes(handler, type_engine, statement_let)? + } Statement::Item(item) => { - let nodes = item_to_ast_nodes(handler, item, false, None)?; + let nodes = item_to_ast_nodes(handler, type_engine, item, false, None)?; nodes.iter().fold(Ok(()), |res, node| { if ast_node_is_test_fn(node) { let span = node.span.clone(); @@ -1783,13 +1868,14 @@ fn statement_to_ast_nodes( })?; nodes } - Statement::Expr { expr, .. } => vec![expr_to_ast_node(handler, expr, true)?], + Statement::Expr { expr, .. } => vec![expr_to_ast_node(handler, type_engine, expr, true)?], }; Ok(ast_nodes) } fn fn_arg_to_function_parameter( handler: &Handler, + type_engine: &TypeEngine, fn_arg: FnArg, ) -> Result { let type_span = fn_arg.ty.span(); @@ -1837,7 +1923,7 @@ fn fn_arg_to_function_parameter( is_reference: reference.is_some(), is_mutable: mutable.is_some(), mutability_span, - type_info: ty_to_type_info(handler, fn_arg.ty)?, + type_info: ty_to_type_info(handler, type_engine, fn_arg.ty)?, type_span, }; Ok(function_parameter) @@ -1959,10 +2045,11 @@ fn path_type_segment_to_ident( /// but allows for the item to be either type arguments _or_ an ident. fn path_expr_segment_to_ident_or_type_argument( handler: &Handler, + type_engine: &TypeEngine, PathExprSegment { name, generics_opt }: PathExprSegment, ) -> Result<(Ident, Vec), ErrorEmitted> { let type_args = match generics_opt { - Some((_, x)) => generic_args_to_type_arguments(handler, x)?, + Some((_, x)) => generic_args_to_type_arguments(handler, type_engine, x)?, None => Default::default(), }; Ok((name, type_args)) @@ -2012,17 +2099,23 @@ fn path_expr_to_expression( fn braced_code_block_contents_to_expression( handler: &Handler, + type_engine: &TypeEngine, braced_code_block_contents: Braces, ) -> Result { let span = braced_code_block_contents.span(); - let code_block = braced_code_block_contents_to_code_block(handler, braced_code_block_contents)?; + let code_block = + braced_code_block_contents_to_code_block(handler, type_engine, braced_code_block_contents)?; Ok(Expression { kind: ExpressionKind::CodeBlock(code_block), span, }) } -fn if_expr_to_expression(handler: &Handler, if_expr: IfExpr) -> Result { +fn if_expr_to_expression( + handler: &Handler, + type_engine: &TypeEngine, + if_expr: IfExpr, +) -> Result { let span = if_expr.span(); let IfExpr { condition, @@ -2033,7 +2126,9 @@ fn if_expr_to_expression(handler: &Handler, if_expr: IfExpr) -> Result Result { let expression = match tail { ControlFlow::Break(braced_code_block_contents) => { - braced_code_block_contents_to_expression(handler, braced_code_block_contents)? + braced_code_block_contents_to_expression( + handler, + type_engine, + braced_code_block_contents, + )? + } + ControlFlow::Continue(if_expr) => { + if_expr_to_expression(handler, type_engine, *if_expr)? } - ControlFlow::Continue(if_expr) => if_expr_to_expression(handler, *if_expr)?, }; Some(expression) } @@ -2052,7 +2153,7 @@ fn if_expr_to_expression(handler: &Handler, if_expr: IfExpr) -> Result Expression { kind: ExpressionKind::If(IfExpression { - condition: Box::new(expr_to_expression(handler, *condition)?), + condition: Box::new(expr_to_expression(handler, type_engine, *condition)?), then: Box::new(then_block), r#else: else_block.map(Box::new), }), @@ -2098,7 +2199,7 @@ fn if_expr_to_expression(handler: &Handler, if_expr: IfExpr) -> Result Result, ErrorEmitted> { let PathExpr { @@ -2274,13 +2376,17 @@ fn path_expr_to_call_path_binding( prefixes.push(ident); } let span = call_path_suffix.span(); - let (suffix, ty_args) = - path_expr_segment_to_ident_or_type_argument(handler, call_path_suffix)?; + let (suffix, ty_args) = path_expr_segment_to_ident_or_type_argument( + handler, + type_engine, + call_path_suffix, + )?; (prefixes, suffix, span, ty_args) } None => { let span = prefix.span(); - let (suffix, ty_args) = path_expr_segment_to_ident_or_type_argument(handler, prefix)?; + let (suffix, ty_args) = + path_expr_segment_to_ident_or_type_argument(handler, type_engine, prefix)?; (vec![], suffix, span, ty_args) } }; @@ -2329,11 +2435,12 @@ fn path_expr_to_call_path( fn expr_struct_field_to_struct_expression_field( handler: &Handler, + type_engine: &TypeEngine, expr_struct_field: ExprStructField, ) -> Result { let span = expr_struct_field.span(); let value = match expr_struct_field.expr_opt { - Some((_colon_token, expr)) => expr_to_expression(handler, *expr)?, + Some((_colon_token, expr)) => expr_to_expression(handler, type_engine, *expr)?, None => Expression { kind: ExpressionKind::Variable(expr_struct_field.field_name.clone()), span: span.clone(), @@ -2348,14 +2455,15 @@ fn expr_struct_field_to_struct_expression_field( fn expr_tuple_descriptor_to_expressions( handler: &Handler, + type_engine: &TypeEngine, expr_tuple_descriptor: ExprTupleDescriptor, ) -> Result, ErrorEmitted> { let expressions = match expr_tuple_descriptor { ExprTupleDescriptor::Nil => Vec::new(), ExprTupleDescriptor::Cons { head, tail, .. } => { - let mut expressions = vec![expr_to_expression(handler, *head)?]; + let mut expressions = vec![expr_to_expression(handler, type_engine, *head)?]; for expr in tail { - expressions.push(expr_to_expression(handler, expr)?); + expressions.push(expr_to_expression(handler, type_engine, expr)?); } expressions } @@ -2365,6 +2473,7 @@ fn expr_tuple_descriptor_to_expressions( fn asm_block_to_asm_expression( handler: &Handler, + type_engine: &TypeEngine, asm_block: AsmBlock, ) -> Result, ErrorEmitted> { let whole_block_span = asm_block.span(); @@ -2376,7 +2485,7 @@ fn asm_block_to_asm_expression( }; let returns = Some((asm_register, asm_final_expr.register.span())); let return_type = match asm_final_expr.ty_opt { - Some((_colon_token, ty)) => ty_to_type_info(handler, ty)?, + Some((_colon_token, ty)) => ty_to_type_info(handler, type_engine, ty)?, None => TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), }; (returns, return_type) @@ -2391,6 +2500,7 @@ fn asm_block_to_asm_expression( .map(|asm_register_declaration| { asm_register_declaration_to_asm_register_declaration( handler, + type_engine, asm_register_declaration, ) }) @@ -2414,6 +2524,7 @@ fn asm_block_to_asm_expression( fn match_branch_to_match_branch( handler: &Handler, + type_engine: &TypeEngine, match_branch: sway_ast::MatchBranch, ) -> Result { let span = match_branch.span(); @@ -2424,12 +2535,14 @@ fn match_branch_to_match_branch( let span = block.span(); Expression { kind: ExpressionKind::CodeBlock(braced_code_block_contents_to_code_block( - handler, block, + handler, + type_engine, + block, )?), span, } } - MatchBranchKind::Expr { expr, .. } => expr_to_expression(handler, expr)?, + MatchBranchKind::Expr { expr, .. } => expr_to_expression(handler, type_engine, expr)?, }, span, }) @@ -2437,10 +2550,12 @@ fn match_branch_to_match_branch( fn statement_let_to_ast_nodes( handler: &Handler, + type_engine: &TypeEngine, statement_let: StatementLet, ) -> Result, ErrorEmitted> { fn unfold( handler: &Handler, + type_engine: &TypeEngine, pattern: Pattern, ty_opt: Option, expression: Expression, @@ -2464,7 +2579,7 @@ fn statement_let_to_ast_nodes( let (type_ascription, type_ascription_span) = match ty_opt { Some(ty) => { let type_ascription_span = ty.span(); - let type_ascription = ty_to_type_info(handler, ty)?; + let type_ascription = ty_to_type_info(handler, type_engine, ty)?; (type_ascription, Some(type_ascription_span)) } None => (TypeInfo::Unknown, None), @@ -2515,7 +2630,7 @@ fn statement_let_to_ast_nodes( let (type_ascription, type_ascription_span) = match &ty_opt { Some(ty) => { let type_ascription_span = ty.span(); - let type_ascription = ty_to_type_info(handler, ty.clone())?; + let type_ascription = ty_to_type_info(handler, type_engine, ty.clone())?; (type_ascription, Some(type_ascription_span)) } None => (TypeInfo::Unknown, None), @@ -2569,6 +2684,7 @@ fn statement_let_to_ast_nodes( // and add them to the ast nodes ast_nodes.extend(unfold( handler, + type_engine, recursive_pattern, None, Expression { @@ -2600,7 +2716,7 @@ fn statement_let_to_ast_nodes( let (type_ascription, type_ascription_span) = match &ty_opt { Some(ty) => { let type_ascription_span = ty.span(); - let type_ascription = ty_to_type_info(handler, ty.clone())?; + let type_ascription = ty_to_type_info(handler, type_engine, ty.clone())?; (type_ascription, Some(type_ascription_span)) } None => (TypeInfo::Unknown, None), @@ -2647,6 +2763,7 @@ fn statement_let_to_ast_nodes( // and add them to the ast nodes ast_nodes.extend(unfold( handler, + type_engine, pattern, ty_opt, Expression { @@ -2666,9 +2783,10 @@ fn statement_let_to_ast_nodes( Ok(ast_nodes) } let span = statement_let.span(); - let initial_expression = expr_to_expression(handler, statement_let.expr)?; + let initial_expression = expr_to_expression(handler, type_engine, statement_let.expr)?; unfold( handler, + type_engine, statement_let.pattern, statement_let.ty_opt.map(|(_colon_token, ty)| ty), initial_expression, @@ -2687,25 +2805,27 @@ fn dependency_to_include_statement(dependency: &Dependency) -> IncludeStatement #[allow(dead_code)] fn generic_args_to_type_parameters( handler: &Handler, + type_engine: &TypeEngine, generic_args: GenericArgs, ) -> Result, ErrorEmitted> { generic_args .parameters .into_inner() .into_iter() - .map(|x| ty_to_type_parameter(handler, x)) + .map(|x| ty_to_type_parameter(handler, type_engine, x)) .collect() } fn asm_register_declaration_to_asm_register_declaration( handler: &Handler, + type_engine: &TypeEngine, asm_register_declaration: sway_ast::AsmRegisterDeclaration, ) -> Result { Ok(AsmRegisterDeclaration { name: asm_register_declaration.register, initializer: asm_register_declaration .value_opt - .map(|(_colon_token, expr)| expr_to_expression(handler, *expr)) + .map(|(_colon_token, expr)| expr_to_expression(handler, type_engine, *expr)) .transpose()?, }) } @@ -2814,11 +2934,15 @@ fn pattern_to_scrutinee(handler: &Handler, pattern: Pattern) -> Result Result { +fn ty_to_type_parameter( + handler: &Handler, + type_engine: &TypeEngine, + ty: Ty, +) -> Result { let name_ident = match ty { Ty::Path(path_type) => path_type_to_ident(handler, path_type)?, Ty::Infer { underscore_token } => { - let unknown_type = insert_type(TypeInfo::Unknown); + let unknown_type = type_engine.insert_type(TypeInfo::Unknown); return Ok(TypeParameter { type_id: unknown_type, initial_type_id: unknown_type, @@ -2831,7 +2955,7 @@ fn ty_to_type_parameter(handler: &Handler, ty: Ty) -> Result panic!("array types are not allowed in this position"), Ty::Str { .. } => panic!("str types are not allowed in this position"), }; - let custom_type = insert_type(TypeInfo::Custom { + let custom_type = type_engine.insert_type(TypeInfo::Custom { name: name_ident.clone(), type_arguments: None, }); @@ -2899,6 +3023,7 @@ fn pattern_struct_field_to_struct_scrutinee_field( fn assignable_to_expression( handler: &Handler, + type_engine: &TypeEngine, assignable: Assignable, ) -> Result { let span = assignable.span(); @@ -2909,8 +3034,8 @@ fn assignable_to_expression( }, Assignable::Index { target, arg } => Expression { kind: ExpressionKind::ArrayIndex(ArrayIndexExpression { - prefix: Box::new(assignable_to_expression(handler, *target)?), - index: Box::new(expr_to_expression(handler, *arg.into_inner())?), + prefix: Box::new(assignable_to_expression(handler, type_engine, *target)?), + index: Box::new(expr_to_expression(handler, type_engine, *arg.into_inner())?), }), span, }, @@ -2944,7 +3069,7 @@ fn assignable_to_expression( } None => Expression { kind: ExpressionKind::Subfield(SubfieldExpression { - prefix: Box::new(assignable_to_expression(handler, *target)?), + prefix: Box::new(assignable_to_expression(handler, type_engine, *target)?), field_to_access: name, }), span, @@ -2966,7 +3091,7 @@ fn assignable_to_expression( }; Expression { kind: ExpressionKind::TupleIndex(TupleIndexExpression { - prefix: Box::new(assignable_to_expression(handler, *target)?), + prefix: Box::new(assignable_to_expression(handler, type_engine, *target)?), index, index_span: field_span, }), @@ -2979,6 +3104,7 @@ fn assignable_to_expression( fn assignable_to_reassignment_target( handler: &Handler, + type_engine: &TypeEngine, assignable: Assignable, ) -> Result { let mut idents = Vec::new(); @@ -3000,12 +3126,13 @@ fn assignable_to_reassignment_target( Assignable::TupleFieldProjection { .. } => break, } } - let expression = assignable_to_expression(handler, assignable)?; + let expression = assignable_to_expression(handler, type_engine, assignable)?; Ok(ReassignmentTarget::VariableExpression(Box::new(expression))) } fn generic_args_to_type_arguments( handler: &Handler, + type_engine: &TypeEngine, generic_args: GenericArgs, ) -> Result, ErrorEmitted> { generic_args @@ -3014,7 +3141,7 @@ fn generic_args_to_type_arguments( .into_iter() .map(|ty| { let span = ty.span(); - let type_id = insert_type(ty_to_type_info(handler, ty)?); + let type_id = type_engine.insert_type(ty_to_type_info(handler, type_engine, ty)?); Ok(TypeArgument { type_id, initial_type_id: type_id, @@ -3026,14 +3153,15 @@ fn generic_args_to_type_arguments( fn ty_tuple_descriptor_to_type_arguments( handler: &Handler, + type_engine: &TypeEngine, ty_tuple_descriptor: TyTupleDescriptor, ) -> Result, ErrorEmitted> { let type_arguments = match ty_tuple_descriptor { TyTupleDescriptor::Nil => vec![], TyTupleDescriptor::Cons { head, tail, .. } => { - let mut type_arguments = vec![ty_to_type_argument(handler, *head)?]; + let mut type_arguments = vec![ty_to_type_argument(handler, type_engine, *head)?]; for ty in tail.into_iter() { - type_arguments.push(ty_to_type_argument(handler, ty)?); + type_arguments.push(ty_to_type_argument(handler, type_engine, ty)?); } type_arguments } @@ -3043,6 +3171,7 @@ fn ty_tuple_descriptor_to_type_arguments( fn path_type_to_type_info( handler: &Handler, + type_engine: &TypeEngine, path_type: PathType, ) -> Result { let span = path_type.span(); @@ -3099,7 +3228,7 @@ fn path_type_to_type_info( } else { let type_arguments = match generics_opt { Some((_double_colon_token, generic_args)) => { - generic_args_to_type_arguments(handler, generic_args)? + generic_args_to_type_arguments(handler, type_engine, generic_args)? } None => Vec::new(), }; diff --git a/sway-core/src/type_system/collect_types_metadata.rs b/sway-core/src/type_system/collect_types_metadata.rs index 68f52f900c4..3614a7910d7 100644 --- a/sway-core/src/type_system/collect_types_metadata.rs +++ b/sway-core/src/type_system/collect_types_metadata.rs @@ -8,7 +8,7 @@ use std::{ sync::{Arc, Mutex}, }; -use crate::{type_system::TypeId, CompileResult}; +use crate::{type_system::TypeId, CompileResult, TypeEngine}; use sway_types::{Ident, Span}; /// If any types contained by this node are unresolved or have yet to be inferred, throw an @@ -38,15 +38,16 @@ pub enum TypeMetadata { } // A simple context that only contains a single counter for now but may expand in the future. -pub struct CollectTypesMetadataContext { +pub struct CollectTypesMetadataContext<'cx> { // Consume this and update it via the methods implemented for CollectTypesMetadataContext to // obtain a unique ID for a given log instance. log_id_counter: usize, call_site_spans: Vec>>>, + pub(crate) type_engine: &'cx TypeEngine, } -impl CollectTypesMetadataContext { +impl<'a> CollectTypesMetadataContext<'a> { pub fn log_id_counter(&self) -> usize { self.log_id_counter } @@ -83,8 +84,9 @@ impl CollectTypesMetadataContext { None } - pub fn new() -> Self { + pub fn new(type_engine: &'a TypeEngine) -> Self { let mut ctx = Self { + type_engine, log_id_counter: 0, call_site_spans: vec![], }; diff --git a/sway-core/src/type_system/copy_types.rs b/sway-core/src/type_system/copy_types.rs index 71a52e3e933..0a5f002fa8a 100644 --- a/sway-core/src/type_system/copy_types.rs +++ b/sway-core/src/type_system/copy_types.rs @@ -1,11 +1,13 @@ +use crate::TypeEngine; + use super::TypeMapping; pub(crate) trait CopyTypes { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping); + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine); - fn copy_types(&mut self, type_mapping: &TypeMapping) { + fn copy_types(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { if !type_mapping.is_empty() { - self.copy_types_inner(type_mapping); + self.copy_types_inner(type_mapping, type_engine); } } } diff --git a/sway-core/src/type_system/create_type_id.rs b/sway-core/src/type_system/create_type_id.rs index 767f450d715..ac885e52447 100644 --- a/sway-core/src/type_system/create_type_id.rs +++ b/sway-core/src/type_system/create_type_id.rs @@ -1,5 +1,5 @@ -use crate::type_system::TypeId; +use crate::{type_system::TypeId, TypeEngine}; pub(crate) trait CreateTypeId { - fn create_type_id(&self) -> TypeId; + fn create_type_id(&self, type_engine: &TypeEngine) -> TypeId; } diff --git a/sway-core/src/type_system/mod.rs b/sway-core/src/type_system/mod.rs index 7ccce86ccb3..1b9a715994a 100644 --- a/sway-core/src/type_system/mod.rs +++ b/sway-core/src/type_system/mod.rs @@ -38,14 +38,13 @@ use sway_types::{integer_bits::IntegerBits, Span}; #[test] fn generic_enum_resolution() { use crate::{language::ty, span::Span, transform, Ident}; - use std::collections::BTreeSet; let engine = TypeEngine::default(); let sp = Span::dummy(); let generic_type = engine.insert_type_always(TypeInfo::UnknownGeneric { name: Ident::new_with_override("T", sp.clone()), - trait_constraints: BTreeSet::new(), + trait_constraints: VecSet(Vec::new()), }); let variant_types = vec![ty::TyEnumVariant { name: Ident::new_with_override("a", sp.clone()), @@ -101,10 +100,10 @@ fn generic_enum_resolution() { } = engine.look_up_type_id(ty_1) { assert_eq!(name.as_str(), "Result"); - assert_eq!( + assert!(matches!( engine.look_up_type_id(variant_types[0].type_id), TypeInfo::Boolean - ); + )); } else { panic!() } @@ -123,10 +122,10 @@ fn basic_numeric_unknown() { let (_, errors) = engine.unify(id, id2, &sp, ""); assert!(errors.is_empty()); - assert_eq!( + assert!(matches!( engine.to_typeinfo(id, &Span::dummy()).unwrap(), TypeInfo::UnsignedInteger(IntegerBits::Eight) - ); + )); } #[test] @@ -142,10 +141,10 @@ fn unify_numerics() { let (_, errors) = engine.unify(id2, id, &sp, ""); assert!(errors.is_empty()); - assert_eq!( + assert!(matches!( engine.to_typeinfo(id, &Span::dummy()).unwrap(), TypeInfo::UnsignedInteger(IntegerBits::Eight) - ); + )); } #[test] @@ -161,8 +160,8 @@ fn unify_numerics_2() { let (_, errors) = engine.unify(id, id2, &sp, ""); assert!(errors.is_empty()); - assert_eq!( + assert!(matches!( engine.to_typeinfo(id, &Span::dummy()).unwrap(), TypeInfo::UnsignedInteger(IntegerBits::Eight) - ); + )); } diff --git a/sway-core/src/type_system/replace_self_type.rs b/sway-core/src/type_system/replace_self_type.rs index 629bb41208d..f302cc61120 100644 --- a/sway-core/src/type_system/replace_self_type.rs +++ b/sway-core/src/type_system/replace_self_type.rs @@ -1,6 +1,8 @@ +use crate::TypeEngine; + use super::TypeId; /// replace any instances of `TypeInfo::SelfType` with a provided [TypeId] `self_type`. pub(crate) trait ReplaceSelfType { - fn replace_self_type(&mut self, self_type: TypeId); + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId); } diff --git a/sway-core/src/type_system/resolved_type.rs b/sway-core/src/type_system/resolved_type.rs index 798c5c0aee0..01a61bf86f7 100644 --- a/sway-core/src/type_system/resolved_type.rs +++ b/sway-core/src/type_system/resolved_type.rs @@ -1,7 +1,5 @@ -use crate::language::{ty, CallPath}; use derivative::Derivative; use sway_types::integer_bits::IntegerBits; -use sway_types::Ident; #[derive(Derivative)] #[derivative(Debug, Clone, Eq, PartialEq, Hash)] @@ -12,6 +10,7 @@ pub enum ResolvedType { Boolean, Unit, B256, + /* #[allow(dead_code)] Struct { name: Ident, @@ -42,6 +41,7 @@ pub enum ResolvedType { /// used for recovering from errors in the ast #[allow(dead_code)] ErrorRecovery, + */ } impl Default for ResolvedType { diff --git a/sway-core/src/type_system/trait_constraint.rs b/sway-core/src/type_system/trait_constraint.rs index e70bb5fc3f4..0841a8b40ed 100644 --- a/sway-core/src/type_system/trait_constraint.rs +++ b/sway-core/src/type_system/trait_constraint.rs @@ -1,3 +1,5 @@ +use std::hash::Hash; + use sway_error::error::CompileError; use sway_types::{Span, Spanned}; @@ -10,12 +12,26 @@ use crate::{ CompileResult, }; -#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +#[derive(Debug, Clone)] pub struct TraitConstraint { pub(crate) trait_name: CallPath, pub(crate) type_arguments: Vec, } +impl HashWithTypeEngine for TraitConstraint { + fn hash(&self, state: &mut H, type_engine: &TypeEngine) { + self.trait_name.hash(state); + self.type_arguments.hash(state, type_engine); + } +} +impl EqWithTypeEngine for TraitConstraint {} +impl PartialEqWithTypeEngine for TraitConstraint { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.trait_name == rhs.trait_name + && self.type_arguments.eq(&rhs.type_arguments, type_engine) + } +} + impl Spanned for TraitConstraint { fn span(&self) -> sway_types::Span { self.trait_name.span() @@ -23,18 +39,18 @@ impl Spanned for TraitConstraint { } impl CopyTypes for TraitConstraint { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { self.type_arguments .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); } } impl ReplaceSelfType for TraitConstraint { - fn replace_self_type(&mut self, self_type: TypeId) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { self.type_arguments .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); } } @@ -116,7 +132,7 @@ impl TraitConstraint { for type_argument in self.type_arguments.iter_mut() { type_argument.type_id = check!( ctx.resolve_type_without_self(type_argument.type_id, &type_argument.span, None), - insert_type(TypeInfo::ErrorRecovery), + ctx.type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors ); diff --git a/sway-core/src/type_system/type_argument.rs b/sway-core/src/type_system/type_argument.rs index 87607cce2d2..fddb4c25db9 100644 --- a/sway-core/src/type_system/type_argument.rs +++ b/sway-core/src/type_system/type_argument.rs @@ -1,17 +1,11 @@ use crate::type_system::*; -use derivative::Derivative; -use std::{ - fmt, - hash::{Hash, Hasher}, -}; +use std::{fmt, hash::Hasher}; use sway_types::{Span, Spanned}; -#[derive(Debug, Clone, Eq, Derivative)] -#[derivative(PartialOrd, Ord)] +#[derive(Debug, Clone)] pub struct TypeArgument { pub type_id: TypeId, pub initial_type_id: TypeId, - #[derivative(PartialOrd = "ignore", Ord = "ignore")] pub span: Span, } @@ -24,35 +18,40 @@ impl Spanned for TypeArgument { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl Hash for TypeArgument { - fn hash(&self, state: &mut H) { - look_up_type_id(self.type_id).hash(state); +impl HashWithTypeEngine for TypeArgument { + fn hash(&self, state: &mut H, type_engine: &TypeEngine) { + type_engine + .look_up_type_id(self.type_id) + .hash(state, type_engine); } } // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TypeArgument { - fn eq(&self, other: &Self) -> bool { - look_up_type_id(self.type_id) == look_up_type_id(other.type_id) +impl EqWithTypeEngine for TypeArgument {} +impl PartialEqWithTypeEngine for TypeArgument { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { + type_engine + .look_up_type_id(self.type_id) + .eq(&type_engine.look_up_type_id(other.type_id), type_engine) } } - -impl Default for TypeArgument { - fn default() -> Self { - let initial_type_id = insert_type(TypeInfo::Unknown); - TypeArgument { - type_id: initial_type_id, - initial_type_id, - span: Span::dummy(), - } +impl OrdWithTypeEngine for TypeArgument { + fn cmp(&self, rhs: &Self, _: &TypeEngine) -> std::cmp::Ordering { + self.type_id + .cmp(&rhs.type_id) + .then_with(|| self.initial_type_id.cmp(&rhs.initial_type_id)) } } -impl fmt::Display for TypeArgument { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", look_up_type_id(self.type_id)) +impl DisplayWithTypeEngine for TypeArgument { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { + write!( + f, + "{}", + type_engine.help_out(type_engine.look_up_type_id(self.type_id)) + ) } } @@ -67,19 +66,21 @@ impl From<&TypeParameter> for TypeArgument { } impl TypeArgument { - pub fn json_abi_str(&self) -> String { - look_up_type_id(self.type_id).json_abi_str() + pub fn json_abi_str(&self, type_engine: &TypeEngine) -> String { + type_engine + .look_up_type_id(self.type_id) + .json_abi_str(type_engine) } } impl ReplaceSelfType for TypeArgument { - fn replace_self_type(&mut self, self_type: TypeId) { - self.type_id.replace_self_type(self_type); + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + self.type_id.replace_self_type(type_engine, self_type); } } impl CopyTypes for TypeArgument { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - self.type_id.copy_types(type_mapping); + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + self.type_id.copy_types(type_mapping, type_engine); } } diff --git a/sway-core/src/type_system/type_binding.rs b/sway-core/src/type_system/type_binding.rs index 374fa9bb39f..72e983202b5 100644 --- a/sway-core/src/type_system/type_binding.rs +++ b/sway-core/src/type_system/type_binding.rs @@ -5,7 +5,7 @@ use crate::{ error::*, language::{ty, CallPath}, semantic_analysis::TypeCheckContext, - type_system::{insert_type, EnforceTypeArguments}, + type_system::EnforceTypeArguments, CreateTypeId, TypeInfo, }; @@ -113,12 +113,12 @@ impl TypeBinding> { // resolve the type of the type info object let type_id = check!( ctx.resolve_type_with_self( - insert_type(type_info), + ctx.type_engine.insert_type(type_info), &type_info_span, EnforceTypeArguments::No, Some(&type_info_prefix) ), - insert_type(TypeInfo::ErrorRecovery), + ctx.type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors ); @@ -145,10 +145,10 @@ impl TypeBinding { // replace the self types inside of the type arguments for type_argument in self.type_arguments.iter_mut() { - type_argument.replace_self_type(ctx.self_type()); + type_argument.replace_self_type(ctx.type_engine, ctx.self_type()); type_argument.type_id = check!( ctx.resolve_type_without_self(type_argument.type_id, &type_argument.span, None), - insert_type(TypeInfo::ErrorRecovery), + ctx.type_engine.insert_type(TypeInfo::ErrorRecovery), warnings, errors ); @@ -206,8 +206,10 @@ impl TypeBinding { ); // take any trait methods that apply to this type and copy them to the new type - ctx.namespace - .insert_trait_implementation_for_type(new_copy.create_type_id()); + ctx.namespace.insert_trait_implementation_for_type( + ctx.type_engine, + new_copy.create_type_id(ctx.type_engine), + ); // insert the new copy into the declaration engine let new_id = de_insert_enum(new_copy); @@ -237,8 +239,10 @@ impl TypeBinding { ); // take any trait methods that apply to this type and copy them to the new type - ctx.namespace - .insert_trait_implementation_for_type(new_copy.create_type_id()); + ctx.namespace.insert_trait_implementation_for_type( + ctx.type_engine, + new_copy.create_type_id(ctx.type_engine), + ); // insert the new copy into the declaration engine let new_id = de_insert_struct(new_copy); diff --git a/sway-core/src/type_system/type_engine.rs b/sway-core/src/type_system/type_engine.rs index 5c24dd64dc4..9b83c1cd102 100644 --- a/sway-core/src/type_system/type_engine.rs +++ b/sway-core/src/type_system/type_engine.rs @@ -1,21 +1,22 @@ +use core::fmt; +use core::hash::{Hash, Hasher}; +use hashbrown::hash_map::RawEntryMut; +use hashbrown::HashMap; +use std::cmp::Ordering; +use std::hash::BuildHasher; use std::sync::RwLock; -use std::{collections::HashMap, fmt}; +use crate::concurrent_slab::ListDisplay; use crate::{ concurrent_slab::ConcurrentSlab, declaration_engine::*, language::ty, namespace::Path, type_system::*, Namespace, }; -use lazy_static::lazy_static; use sway_error::{error::CompileError, type_error::TypeError, warning::CompileWarning}; use sway_types::{span::Span, Ident, Spanned}; -lazy_static! { - static ref TYPE_ENGINE: TypeEngine = TypeEngine::default(); -} - #[derive(Debug, Default)] -pub(crate) struct TypeEngine { +pub struct TypeEngine { pub(super) slab: ConcurrentSlab, storage_only_types: ConcurrentSlab, id_map: RwLock>, @@ -23,7 +24,25 @@ pub(crate) struct TypeEngine { impl fmt::Display for TypeEngine { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "DeclarationEngine {{\n{}\n}}", self.slab) + self.slab.with_slice(|elems| { + let list = elems.iter().map(|type_info| self.help_out(type_info)); + let list = ListDisplay { list }; + write!(f, "TypeEngine {{\n{}\n}}", list) + }) + } +} + +fn make_hasher<'a: 'b, 'b, K>( + hash_builder: &'a impl BuildHasher, + type_engine: &'b TypeEngine, +) -> impl Fn(&K) -> u64 + 'b +where + K: HashWithTypeEngine + ?Sized, +{ + move |key: &K| { + let mut state = hash_builder.build_hasher(); + key.hash(&mut state, type_engine); + state.finish() } } @@ -32,15 +51,21 @@ impl TypeEngine { /// referring to that [TypeInfo]. pub(crate) fn insert_type(&self, ty: TypeInfo) -> TypeId { let mut id_map = self.id_map.write().unwrap(); - if let Some(type_id) = id_map.get(&ty) { - return *type_id; - } - if ty.can_change() { - TypeId::new(self.slab.insert(ty)) - } else { - let type_id = TypeId::new(self.slab.insert(ty.clone())); - id_map.insert(ty, type_id); - type_id + + let hash_builder = id_map.hasher().clone(); + let ty_hash = make_hasher(&hash_builder, self)(&ty); + + let raw_entry = id_map + .raw_entry_mut() + .from_hash(ty_hash, |x| x.eq(&ty, self)); + match raw_entry { + RawEntryMut::Occupied(o) => return *o.get(), + RawEntryMut::Vacant(_) if ty.can_change() => TypeId::new(self.slab.insert(ty)), + RawEntryMut::Vacant(v) => { + let type_id = TypeId::new(self.slab.insert(ty.clone())); + v.insert_with_hasher(ty_hash, ty, type_id, make_hasher(&hash_builder, self)); + type_id + } } } @@ -56,30 +81,19 @@ impl TypeEngine { TypeId::new(self.slab.insert(ty)) } - /// Gets the size of the [TypeEngine]. - fn size(&self) -> usize { - self.slab.size() - } - /// Performs a lookup of `id` into the [TypeEngine]. - pub(crate) fn look_up_type_id(&self, id: TypeId) -> TypeInfo { - self.slab.get(*id) + pub fn look_up_type_id(&self, id: TypeId) -> TypeInfo { + self.slab.get(id.index()) } /// Denotes the given [TypeId] as being used with storage. - fn set_type_as_storage_only(&self, id: TypeId) { + pub(crate) fn set_type_as_storage_only(&self, id: TypeId) { self.storage_only_types.insert(self.look_up_type_id(id)); } - /// Checks if the given [TypeId] is a storage only type. - fn is_type_storage_only(&self, id: TypeId) -> bool { - let ti = &self.look_up_type_id(id); - self.is_type_info_storage_only(ti) - } - /// Checks if the given [TypeInfo] is a storage only type. - fn is_type_info_storage_only(&self, ti: &TypeInfo) -> bool { - self.storage_only_types.exists(|x| ti.is_subset_of(x)) + pub(crate) fn is_type_info_storage_only(&self, ti: &TypeInfo) -> bool { + self.storage_only_types.exists(|x| ti.is_subset_of(x, self)) } /// Given a `value` of type `T` that is able to be monomorphized and a set @@ -112,7 +126,7 @@ impl TypeEngine { /// the same length /// 4b. for each type argument in `type_arguments`, resolve the type /// 4c. refresh the generic types with a [TypeMapping] - fn monomorphize( + pub(crate) fn monomorphize( &self, value: &mut T, type_arguments: &mut [TypeArgument], @@ -139,8 +153,8 @@ impl TypeEngine { }); return err(warnings, errors); } - let type_mapping = TypeMapping::from_type_parameters(value.type_parameters()); - value.copy_types(&type_mapping); + let type_mapping = TypeMapping::from_type_parameters(value.type_parameters(), self); + value.copy_types(&type_mapping, self); ok((), warnings, errors) } (true, false) => { @@ -195,7 +209,7 @@ impl TypeEngine { .map(|type_arg| type_arg.type_id) .collect(), ); - value.copy_types(&type_mapping); + value.copy_types(&type_mapping, self); ok((), warnings, errors) } } @@ -204,16 +218,16 @@ impl TypeEngine { /// Replace any instances of the [TypeInfo::SelfType] variant with /// `self_type` in both `received` and `expected`, then unify `received` and /// `expected`. - fn unify_with_self( + pub(crate) fn unify_with_self( &self, mut received: TypeId, mut expected: TypeId, self_type: TypeId, span: &Span, help_text: &str, - ) -> (Vec, Vec) { - received.replace_self_type(self_type); - expected.replace_self_type(self_type); + ) -> (Vec, Vec) { + received.replace_self_type(self, self_type); + expected.replace_self_type(self, self_type); self.unify(received, expected, span, help_text) } @@ -230,23 +244,25 @@ impl TypeEngine { expected: TypeId, span: &Span, help_text: &str, - ) -> (Vec, Vec) { - unify::unify(self, received, expected, span, help_text, false) + ) -> (Vec, Vec) { + normalize_err(unify::unify( + self, received, expected, span, help_text, false, + )) } /// Replace any instances of the [TypeInfo::SelfType] variant with /// `self_type` in both `received` and `expected`, then unify_right /// `received` and `expected`. - fn unify_right_with_self( + pub(crate) fn unify_right_with_self( &self, mut received: TypeId, mut expected: TypeId, self_type: TypeId, span: &Span, help_text: &str, - ) -> (Vec, Vec) { - received.replace_self_type(self_type); - expected.replace_self_type(self_type); + ) -> (Vec, Vec) { + received.replace_self_type(self, self_type); + expected.replace_self_type(self, self_type); self.unify_right(received, expected, span, help_text) } @@ -288,14 +304,16 @@ impl TypeEngine { /// `T` is not valid under the type `bool`. /// /// This is the function that makes that distinction for us! - fn unify_right( + pub(crate) fn unify_right( &self, received: TypeId, expected: TypeId, span: &Span, help_text: &str, - ) -> (Vec, Vec) { - unify::unify_right(self, received, expected, span, help_text) + ) -> (Vec, Vec) { + normalize_err(unify::unify_right( + self, received, expected, span, help_text, + )) } /// Helper function for making the type of `expected` equivalent to @@ -342,17 +360,19 @@ impl TypeEngine { /// What's important about this is flipping the arguments prioritizes /// unifying `expected`, meaning if both `received` and `expected` are /// generic types, then `expected` will be replaced with `received`. - fn unify_adt( + pub(crate) fn unify_adt( &self, received: TypeId, expected: TypeId, span: &Span, help_text: &str, - ) -> (Vec, Vec) { - unify::unify(self, expected, received, span, help_text, true) + ) -> (Vec, Vec) { + normalize_err(unify::unify( + self, expected, received, span, help_text, true, + )) } - pub fn to_typeinfo(&self, id: TypeId, error_span: &Span) -> Result { + pub(crate) fn to_typeinfo(&self, id: TypeId, error_span: &Span) -> Result { match self.look_up_type_id(id) { TypeInfo::Unknown => Err(TypeError::UnknownType { span: error_span.clone(), @@ -361,18 +381,10 @@ impl TypeEngine { } } - /// Clear the [TypeEngine]. - fn clear(&self) { - self.slab.clear(); - self.storage_only_types.clear(); - let mut id_map = self.id_map.write().unwrap(); - id_map.clear(); - } - /// Resolve the type of the given [TypeId], replacing any instances of /// [TypeInfo::Custom] with either a monomorphized struct, monomorphized /// enum, or a reference to a type parameter. - fn resolve_type( + pub(crate) fn resolve_type( &self, type_id: TypeId, span: &Span, @@ -384,7 +396,7 @@ impl TypeEngine { let mut warnings = vec![]; let mut errors = vec![]; let module_path = type_info_prefix.unwrap_or(mod_path); - let type_id = match look_up_type_id(type_id) { + let type_id = match self.look_up_type_id(type_id) { TypeInfo::Custom { name, type_arguments, @@ -420,10 +432,10 @@ impl TypeEngine { ); // create the type id from the copy - let type_id = new_copy.create_type_id(); + let type_id = new_copy.create_type_id(self); // take any trait methods that apply to this type and copy them to the new type - namespace.insert_trait_implementation_for_type(type_id); + namespace.insert_trait_implementation_for_type(self, type_id); // return the id type_id @@ -453,10 +465,10 @@ impl TypeEngine { ); // create the type id from the copy - let type_id = new_copy.create_type_id(); + let type_id = new_copy.create_type_id(self); // take any trait methods that apply to this type and copy them to the new type - namespace.insert_trait_implementation_for_type(type_id); + namespace.insert_trait_implementation_for_type(self, type_id); // return the id type_id @@ -513,7 +525,7 @@ impl TypeEngine { /// Replace any instances of the [TypeInfo::SelfType] variant with /// `self_type` in `type_id`, then resolve `type_id`. #[allow(clippy::too_many_arguments)] - fn resolve_type_with_self( + pub(crate) fn resolve_type_with_self( &self, mut type_id: TypeId, self_type: TypeId, @@ -523,7 +535,7 @@ impl TypeEngine { namespace: &mut Namespace, mod_path: &Path, ) -> CompileResult { - type_id.replace_self_type(self_type); + type_id.replace_self_type(self, self_type); self.resolve_type( type_id, span, @@ -533,171 +545,20 @@ impl TypeEngine { mod_path, ) } -} - -#[allow(dead_code)] -pub(crate) fn print_type_engine() { - println!("{}", &*TYPE_ENGINE); -} - -pub fn insert_type(ty: TypeInfo) -> TypeId { - TYPE_ENGINE.insert_type(ty) -} - -pub fn type_engine_size() -> usize { - TYPE_ENGINE.size() -} - -pub fn look_up_type_id(id: TypeId) -> TypeInfo { - TYPE_ENGINE.look_up_type_id(id) -} - -pub fn set_type_as_storage_only(id: TypeId) { - TYPE_ENGINE.set_type_as_storage_only(id); -} -pub fn is_type_storage_only(id: TypeId) -> bool { - TYPE_ENGINE.is_type_storage_only(id) -} - -pub fn is_type_info_storage_only(ti: &TypeInfo) -> bool { - TYPE_ENGINE.is_type_info_storage_only(ti) -} - -pub(crate) fn monomorphize( - value: &mut T, - type_arguments: &mut [TypeArgument], - enforce_type_arguments: EnforceTypeArguments, - call_site_span: &Span, - namespace: &mut Namespace, - module_path: &Path, -) -> CompileResult<()> -where - T: MonomorphizeHelper + CopyTypes, -{ - TYPE_ENGINE.monomorphize( - value, - type_arguments, - enforce_type_arguments, - call_site_span, - namespace, - module_path, - ) -} - -pub fn unify_with_self( - received: TypeId, - expected: TypeId, - self_type: TypeId, - span: &Span, - help_text: &str, -) -> (Vec, Vec) { - let (warnings, errors) = - TYPE_ENGINE.unify_with_self(received, expected, self_type, span, help_text); - ( - warnings, - errors.into_iter().map(|error| error.into()).collect(), - ) -} - -pub(crate) fn unify( - received: TypeId, - expected: TypeId, - span: &Span, - help_text: &str, -) -> (Vec, Vec) { - let (warnings, errors) = TYPE_ENGINE.unify(received, expected, span, help_text); - ( - warnings, - errors.into_iter().map(|error| error.into()).collect(), - ) -} - -pub(crate) fn unify_right_with_self( - received: TypeId, - expected: TypeId, - self_type: TypeId, - span: &Span, - help_text: &str, -) -> (Vec, Vec) { - let (warnings, errors) = - TYPE_ENGINE.unify_right_with_self(received, expected, self_type, span, help_text); - ( - warnings, - errors.into_iter().map(|error| error.into()).collect(), - ) -} - -pub(crate) fn unify_right( - received: TypeId, - expected: TypeId, - span: &Span, - help_text: &str, -) -> (Vec, Vec) { - let (warnings, errors) = TYPE_ENGINE.unify_right(received, expected, span, help_text); - ( - warnings, - errors.into_iter().map(|error| error.into()).collect(), - ) + /// Helps out some `thing: T` by adding `self` as context. + pub fn help_out(&self, thing: T) -> WithTypeEngine<'_, T> { + WithTypeEngine { + thing, + engine: self, + } + } } -pub(crate) fn unify_adt( - received: TypeId, - expected: TypeId, - span: &Span, - help_text: &str, +fn normalize_err( + (w, e): (Vec, Vec), ) -> (Vec, Vec) { - let (warnings, errors) = TYPE_ENGINE.unify_adt(received, expected, span, help_text); - ( - warnings, - errors.into_iter().map(|error| error.into()).collect(), - ) -} - -pub(crate) fn to_typeinfo(id: TypeId, error_span: &Span) -> Result { - TYPE_ENGINE.to_typeinfo(id, error_span) -} - -pub fn clear_type_engine() { - TYPE_ENGINE.clear(); -} - -pub(crate) fn resolve_type( - type_id: TypeId, - span: &Span, - enforce_type_arguments: EnforceTypeArguments, - type_info_prefix: Option<&Path>, - namespace: &mut Namespace, - mod_path: &Path, -) -> CompileResult { - TYPE_ENGINE.resolve_type( - type_id, - span, - enforce_type_arguments, - type_info_prefix, - namespace, - mod_path, - ) -} - -pub(crate) fn resolve_type_with_self( - type_id: TypeId, - self_type: TypeId, - span: &Span, - enforce_type_arguments: EnforceTypeArguments, - type_info_prefix: Option<&Path>, - namespace: &mut Namespace, - mod_path: &Path, -) -> CompileResult { - TYPE_ENGINE.resolve_type_with_self( - type_id, - self_type, - span, - enforce_type_arguments, - type_info_prefix, - namespace, - mod_path, - ) + (w, e.into_iter().map(CompileError::from).collect()) } pub(crate) trait MonomorphizeHelper { @@ -739,3 +600,125 @@ pub(crate) enum EnforceTypeArguments { Yes, No, } + +pub(crate) trait DisplayWithTypeEngine { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result; +} + +impl DisplayWithTypeEngine for &T { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { + (*self).fmt(f, type_engine) + } +} + +pub trait HashWithTypeEngine { + fn hash(&self, state: &mut H, type_engine: &TypeEngine); +} + +impl HashWithTypeEngine for &T { + fn hash(&self, state: &mut H, type_engine: &TypeEngine) { + (*self).hash(state, type_engine) + } +} + +impl HashWithTypeEngine for Option { + fn hash(&self, state: &mut H, type_engine: &TypeEngine) { + match self { + None => state.write_u8(0), + Some(x) => x.hash(state, type_engine), + } + } +} + +impl HashWithTypeEngine for [T] { + fn hash(&self, state: &mut H, type_engine: &TypeEngine) { + for x in self { + x.hash(state, type_engine) + } + } +} + +pub trait EqWithTypeEngine: PartialEqWithTypeEngine {} + +pub trait PartialEqWithTypeEngine { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool; +} + +pub trait OrdWithTypeEngine { + fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> Ordering; +} + +impl EqWithTypeEngine for &T {} +impl PartialEqWithTypeEngine for &T { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + (*self).eq(*rhs, type_engine) + } +} +impl OrdWithTypeEngine for &T { + fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> Ordering { + (*self).cmp(*rhs, type_engine) + } +} + +impl EqWithTypeEngine for Option {} +impl PartialEqWithTypeEngine for Option { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + match (self, rhs) { + (None, None) => true, + (Some(x), Some(y)) => x.eq(y, type_engine), + _ => false, + } + } +} + +impl EqWithTypeEngine for [T] {} +impl PartialEqWithTypeEngine for [T] { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.len() == rhs.len() + && self + .iter() + .zip(rhs.iter()) + .all(|(x, y)| x.eq(y, type_engine)) + } +} +impl OrdWithTypeEngine for [T] { + fn cmp(&self, rhs: &Self, type_engine: &TypeEngine) -> Ordering { + self.iter() + .zip(rhs.iter()) + .map(|(x, y)| x.cmp(y, type_engine)) + .find(|o| o.is_ne()) + .unwrap_or_else(|| self.len().cmp(&rhs.len())) + } +} + +#[derive(Clone, Copy)] +pub struct WithTypeEngine<'a, T> { + pub thing: T, + pub engine: &'a TypeEngine, +} + +impl<'a, T> WithTypeEngine<'a, T> { + pub fn new(thing: T, engine: &'a TypeEngine) -> Self { + WithTypeEngine { thing, engine } + } +} + +impl fmt::Display for WithTypeEngine<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.thing.fmt(f, self.engine) + } +} + +impl Hash for WithTypeEngine<'_, T> { + fn hash(&self, state: &mut H) { + self.thing.hash(state, self.engine) + } +} + +impl PartialEq for WithTypeEngine<'_, T> { + fn eq(&self, rhs: &Self) -> bool { + self.thing.eq(&rhs.thing, self.engine) + } +} + +impl Eq for WithTypeEngine<'_, T> {} diff --git a/sway-core/src/type_system/type_id.rs b/sway-core/src/type_system/type_id.rs index 146815afcd8..e23c8caa13d 100644 --- a/sway-core/src/type_system/type_id.rs +++ b/sway-core/src/type_system/type_id.rs @@ -3,25 +3,16 @@ use std::fmt; use sway_types::{JsonTypeApplication, JsonTypeDeclaration}; /// A identifier to uniquely refer to our type terms -#[derive(PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd)] +#[derive(PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd, Debug)] pub struct TypeId(usize); -impl std::ops::Deref for TypeId { - type Target = usize; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl fmt::Display for TypeId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", look_up_type_id(*self)) - } -} - -impl fmt::Debug for TypeId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", look_up_type_id(*self)) +impl DisplayWithTypeEngine for TypeId { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { + write!( + f, + "{}", + type_engine.help_out(type_engine.look_up_type_id(*self)) + ) } } @@ -42,7 +33,7 @@ impl CollectTypesMetadata for TypeId { if let TypeInfo::UnknownGeneric { name, trait_constraints, - } = look_up_type_id(*self) + } = ctx.type_engine.look_up_type_id(*self) { res.push(TypeMetadata::UnresolvedType(name, ctx.call_site_get(self))); for trait_constraint in trait_constraints.iter() { @@ -63,8 +54,8 @@ impl CollectTypesMetadata for TypeId { } impl ReplaceSelfType for TypeId { - fn replace_self_type(&mut self, self_type: TypeId) { - match look_up_type_id(*self) { + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + match type_engine.look_up_type_id(*self) { TypeInfo::SelfType => { *self = self_type; } @@ -74,10 +65,10 @@ impl ReplaceSelfType for TypeId { .. } => { for type_parameter in type_parameters.iter_mut() { - type_parameter.replace_self_type(self_type); + type_parameter.replace_self_type(type_engine, self_type); } for variant_type in variant_types.iter_mut() { - variant_type.replace_self_type(self_type); + variant_type.replace_self_type(type_engine, self_type); } } TypeInfo::Struct { @@ -86,30 +77,30 @@ impl ReplaceSelfType for TypeId { .. } => { for type_parameter in type_parameters.iter_mut() { - type_parameter.replace_self_type(self_type); + type_parameter.replace_self_type(type_engine, self_type); } for field in fields.iter_mut() { - field.replace_self_type(self_type); + field.replace_self_type(type_engine, self_type); } } TypeInfo::Tuple(mut type_arguments) => { for type_argument in type_arguments.iter_mut() { - type_argument.replace_self_type(self_type); + type_argument.replace_self_type(type_engine, self_type); } } TypeInfo::Custom { type_arguments, .. } => { if let Some(mut type_arguments) = type_arguments { for type_argument in type_arguments.iter_mut() { - type_argument.replace_self_type(self_type); + type_argument.replace_self_type(type_engine, self_type); } } } TypeInfo::Array(mut type_id, _, _) => { - type_id.replace_self_type(self_type); + type_id.replace_self_type(type_engine, self_type); } TypeInfo::Storage { mut fields } => { for field in fields.iter_mut() { - field.replace_self_type(self_type); + field.replace_self_type(type_engine, self_type); } } TypeInfo::Unknown @@ -129,16 +120,22 @@ impl ReplaceSelfType for TypeId { } impl CopyTypes for TypeId { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - if let Some(matching_id) = type_mapping.find_match(*self) { + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + if let Some(matching_id) = type_mapping.find_match(*self, type_engine) { *self = matching_id; } } } impl UnconstrainedTypeParameters for TypeId { - fn type_parameter_is_unconstrained(&self, type_parameter: &TypeParameter) -> bool { - look_up_type_id(*self).type_parameter_is_unconstrained(type_parameter) + fn type_parameter_is_unconstrained( + &self, + type_engine: &TypeEngine, + type_parameter: &TypeParameter, + ) -> bool { + type_engine + .look_up_type_id(*self) + .type_parameter_is_unconstrained(type_engine, type_parameter) } } @@ -147,8 +144,16 @@ impl TypeId { TypeId(index) } - pub(crate) fn get_type_parameters(&self) -> Option> { - match look_up_type_id(*self) { + /// Returns the index that identifies the type. + pub fn index(&self) -> usize { + self.0 + } + + pub(crate) fn get_type_parameters( + &self, + type_engine: &TypeEngine, + ) -> Option> { + match type_engine.look_up_type_id(*self) { TypeInfo::Enum { type_parameters, .. } => (!type_parameters.is_empty()).then_some(type_parameters), @@ -162,8 +167,15 @@ impl TypeId { /// Indicates of a given type is generic or not. Rely on whether the type is `Custom` and /// consider the special case where the resolved type is a struct or enum with a name that /// matches the name of the `Custom`. - pub(crate) fn is_generic_parameter(self, resolved_type_id: TypeId) -> bool { - match (look_up_type_id(self), look_up_type_id(resolved_type_id)) { + pub(crate) fn is_generic_parameter( + self, + type_engine: &TypeEngine, + resolved_type_id: TypeId, + ) -> bool { + match ( + type_engine.look_up_type_id(self), + type_engine.look_up_type_id(resolved_type_id), + ) { ( TypeInfo::Custom { name, .. }, TypeInfo::Enum { @@ -187,21 +199,28 @@ impl TypeId { /// discovered types. pub(crate) fn get_json_type_components( &self, + type_engine: &TypeEngine, types: &mut Vec, resolved_type_id: TypeId, ) -> Option> { - match look_up_type_id(*self) { + match type_engine.look_up_type_id(*self) { TypeInfo::Enum { variant_types, .. } => { // A list of all `JsonTypeDeclaration`s needed for the enum variants let variants = variant_types .iter() .map(|x| JsonTypeDeclaration { - type_id: *x.initial_type_id, - type_field: x.initial_type_id.get_json_type_str(x.type_id), - components: x.initial_type_id.get_json_type_components(types, x.type_id), - type_parameters: x - .initial_type_id - .get_json_type_parameters(types, x.type_id), + type_id: x.initial_type_id.index(), + type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), + components: x.initial_type_id.get_json_type_components( + type_engine, + types, + x.type_id, + ), + type_parameters: x.initial_type_id.get_json_type_parameters( + type_engine, + types, + x.type_id, + ), }) .collect::>(); types.extend(variants); @@ -213,10 +232,12 @@ impl TypeId { .iter() .map(|x| JsonTypeApplication { name: x.name.to_string(), - type_id: *x.initial_type_id, - type_arguments: x - .initial_type_id - .get_json_type_arguments(types, x.type_id), + type_id: x.initial_type_id.index(), + type_arguments: x.initial_type_id.get_json_type_arguments( + type_engine, + types, + x.type_id, + ), }) .collect(), ) @@ -226,12 +247,18 @@ impl TypeId { let field_types = fields .iter() .map(|x| JsonTypeDeclaration { - type_id: *x.initial_type_id, - type_field: x.initial_type_id.get_json_type_str(x.type_id), - components: x.initial_type_id.get_json_type_components(types, x.type_id), - type_parameters: x - .initial_type_id - .get_json_type_parameters(types, x.type_id), + type_id: x.initial_type_id.index(), + type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), + components: x.initial_type_id.get_json_type_components( + type_engine, + types, + x.type_id, + ), + type_parameters: x.initial_type_id.get_json_type_parameters( + type_engine, + types, + x.type_id, + ), }) .collect::>(); types.extend(field_types); @@ -243,24 +270,34 @@ impl TypeId { .iter() .map(|x| JsonTypeApplication { name: x.name.to_string(), - type_id: *x.initial_type_id, - type_arguments: x - .initial_type_id - .get_json_type_arguments(types, x.type_id), + type_id: x.initial_type_id.index(), + type_arguments: x.initial_type_id.get_json_type_arguments( + type_engine, + types, + x.type_id, + ), }) .collect(), ) } TypeInfo::Array(..) => { if let TypeInfo::Array(type_id, _, initial_type_id) = - look_up_type_id(resolved_type_id) + type_engine.look_up_type_id(resolved_type_id) { // The `JsonTypeDeclaration`s needed for the array element type let elem_ty = JsonTypeDeclaration { - type_id: *initial_type_id, - type_field: initial_type_id.get_json_type_str(type_id), - components: initial_type_id.get_json_type_components(types, type_id), - type_parameters: initial_type_id.get_json_type_parameters(types, type_id), + type_id: initial_type_id.index(), + type_field: initial_type_id.get_json_type_str(type_engine, type_id), + components: initial_type_id.get_json_type_components( + type_engine, + types, + type_id, + ), + type_parameters: initial_type_id.get_json_type_parameters( + type_engine, + types, + type_id, + ), }; types.push(elem_ty); @@ -268,27 +305,35 @@ impl TypeId { // `JsonTypeApplication` for the array element type Some(vec![JsonTypeApplication { name: "__array_element".to_string(), - type_id: *initial_type_id, - type_arguments: initial_type_id.get_json_type_arguments(types, type_id), + type_id: initial_type_id.index(), + type_arguments: initial_type_id.get_json_type_arguments( + type_engine, + types, + type_id, + ), }]) } else { unreachable!(); } } TypeInfo::Tuple(_) => { - if let TypeInfo::Tuple(fields) = look_up_type_id(resolved_type_id) { + if let TypeInfo::Tuple(fields) = type_engine.look_up_type_id(resolved_type_id) { // A list of all `JsonTypeDeclaration`s needed for the tuple fields let fields_types = fields .iter() .map(|x| JsonTypeDeclaration { - type_id: *x.initial_type_id, - type_field: x.initial_type_id.get_json_type_str(x.type_id), - components: x - .initial_type_id - .get_json_type_components(types, x.type_id), - type_parameters: x - .initial_type_id - .get_json_type_parameters(types, x.type_id), + type_id: x.initial_type_id.index(), + type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id), + components: x.initial_type_id.get_json_type_components( + type_engine, + types, + x.type_id, + ), + type_parameters: x.initial_type_id.get_json_type_parameters( + type_engine, + types, + x.type_id, + ), }) .collect::>(); types.extend(fields_types); @@ -300,10 +345,12 @@ impl TypeId { .iter() .map(|x| JsonTypeApplication { name: "__tuple_element".to_string(), - type_id: *x.initial_type_id, - type_arguments: x - .initial_type_id - .get_json_type_arguments(types, x.type_id), + type_id: x.initial_type_id.index(), + type_arguments: x.initial_type_id.get_json_type_arguments( + type_engine, + types, + x.type_id, + ), }) .collect(), ) @@ -312,31 +359,35 @@ impl TypeId { } } TypeInfo::Custom { type_arguments, .. } => { - if !self.is_generic_parameter(resolved_type_id) { + if !self.is_generic_parameter(type_engine, resolved_type_id) { // A list of all `JsonTypeDeclaration`s needed for the type arguments let type_args = type_arguments .unwrap_or_default() .iter() .zip( resolved_type_id - .get_type_parameters() + .get_type_parameters(type_engine) .unwrap_or_default() .iter(), ) .map(|(v, p)| JsonTypeDeclaration { - type_id: *v.initial_type_id, - type_field: v.initial_type_id.get_json_type_str(p.type_id), - components: v - .initial_type_id - .get_json_type_components(types, p.type_id), - type_parameters: v - .initial_type_id - .get_json_type_parameters(types, p.type_id), + type_id: v.initial_type_id.index(), + type_field: v.initial_type_id.get_json_type_str(type_engine, p.type_id), + components: v.initial_type_id.get_json_type_components( + type_engine, + types, + p.type_id, + ), + type_parameters: v.initial_type_id.get_json_type_parameters( + type_engine, + types, + p.type_id, + ), }) .collect::>(); types.extend(type_args); - resolved_type_id.get_json_type_components(types, resolved_type_id) + resolved_type_id.get_json_type_components(type_engine, types, resolved_type_id) } else { None } @@ -351,14 +402,15 @@ impl TypeId { /// provide list of `JsonTypeDeclaration`s to add the newly discovered types. pub(crate) fn get_json_type_parameters( &self, + type_engine: &TypeEngine, types: &mut Vec, resolved_type_id: TypeId, ) -> Option> { - match self.is_generic_parameter(resolved_type_id) { + match self.is_generic_parameter(type_engine, resolved_type_id) { true => None, - false => resolved_type_id.get_type_parameters().map(|v| { + false => resolved_type_id.get_type_parameters(type_engine).map(|v| { v.iter() - .map(|v| v.get_json_type_parameter(types)) + .map(|v| v.get_json_type_parameter(type_engine, types)) .collect::>() }), } @@ -370,11 +422,12 @@ impl TypeId { /// discovered types. pub(crate) fn get_json_type_arguments( &self, + type_engine: &TypeEngine, types: &mut Vec, resolved_type_id: TypeId, ) -> Option> { - let resolved_params = resolved_type_id.get_type_parameters(); - match look_up_type_id(*self) { + let resolved_params = resolved_type_id.get_type_parameters(type_engine); + match type_engine.look_up_type_id(*self) { TypeInfo::Custom { type_arguments: Some(type_arguments), .. @@ -384,12 +437,18 @@ impl TypeId { .iter() .zip(resolved_params.iter()) .map(|(v, p)| JsonTypeDeclaration { - type_id: *v.initial_type_id, - type_field: v.initial_type_id.get_json_type_str(p.type_id), - components: v.initial_type_id.get_json_type_components(types, p.type_id), - type_parameters: v - .initial_type_id - .get_json_type_parameters(types, p.type_id), + type_id: v.initial_type_id.index(), + type_field: v.initial_type_id.get_json_type_str(type_engine, p.type_id), + components: v.initial_type_id.get_json_type_components( + type_engine, + types, + p.type_id, + ), + type_parameters: v.initial_type_id.get_json_type_parameters( + type_engine, + types, + p.type_id, + ), }) .collect::>(); types.extend(json_type_arguments); @@ -398,10 +457,12 @@ impl TypeId { .iter() .map(|arg| JsonTypeApplication { name: "".to_string(), - type_id: *arg.initial_type_id, - type_arguments: arg - .initial_type_id - .get_json_type_arguments(types, arg.type_id), + type_id: arg.initial_type_id.index(), + type_arguments: arg.initial_type_id.get_json_type_arguments( + type_engine, + types, + arg.type_id, + ), }) .collect::>() }), @@ -415,10 +476,18 @@ impl TypeId { let json_type_arguments = type_parameters .iter() .map(|v| JsonTypeDeclaration { - type_id: *v.type_id, - type_field: v.type_id.get_json_type_str(v.type_id), - components: v.type_id.get_json_type_components(types, v.type_id), - type_parameters: v.type_id.get_json_type_parameters(types, v.type_id), + type_id: v.type_id.index(), + type_field: v.type_id.get_json_type_str(type_engine, v.type_id), + components: v.type_id.get_json_type_components( + type_engine, + types, + v.type_id, + ), + type_parameters: v.type_id.get_json_type_parameters( + type_engine, + types, + v.type_id, + ), }) .collect::>(); types.extend(json_type_arguments); @@ -428,8 +497,12 @@ impl TypeId { .iter() .map(|arg| JsonTypeApplication { name: "".to_string(), - type_id: *arg.type_id, - type_arguments: arg.type_id.get_json_type_arguments(types, arg.type_id), + type_id: arg.type_id.index(), + type_arguments: arg.type_id.get_json_type_arguments( + type_engine, + types, + arg.type_id, + ), }) .collect::>(), ) @@ -438,21 +511,37 @@ impl TypeId { } } - pub fn json_abi_str(&self) -> String { - look_up_type_id(*self).json_abi_str() + pub fn json_abi_str(&self, type_engine: &TypeEngine) -> String { + type_engine.look_up_type_id(*self).json_abi_str(type_engine) } /// Gives back a string that represents the type, considering what it resolves to - pub(crate) fn get_json_type_str(&self, resolved_type_id: TypeId) -> String { - if self.is_generic_parameter(resolved_type_id) { - format!("generic {}", look_up_type_id(*self).json_abi_str()) + pub(crate) fn get_json_type_str( + &self, + type_engine: &TypeEngine, + resolved_type_id: TypeId, + ) -> String { + if self.is_generic_parameter(type_engine, resolved_type_id) { + format!( + "generic {}", + type_engine.look_up_type_id(*self).json_abi_str(type_engine) + ) } else { - match (look_up_type_id(*self), look_up_type_id(resolved_type_id)) { + match ( + type_engine.look_up_type_id(*self), + type_engine.look_up_type_id(resolved_type_id), + ) { (TypeInfo::Custom { .. }, TypeInfo::Struct { .. }) => { - format!("struct {}", look_up_type_id(*self).json_abi_str()) + format!( + "struct {}", + type_engine.look_up_type_id(*self).json_abi_str(type_engine) + ) } (TypeInfo::Custom { .. }, TypeInfo::Enum { .. }) => { - format!("enum {}", look_up_type_id(*self).json_abi_str()) + format!( + "enum {}", + type_engine.look_up_type_id(*self).json_abi_str(type_engine) + ) } (TypeInfo::Tuple(fields), TypeInfo::Tuple(resolved_fields)) => { assert_eq!(fields.len(), resolved_fields.len()); @@ -467,9 +556,12 @@ impl TypeId { format!("[_; {count}]") } (TypeInfo::Custom { .. }, _) => { - format!("generic {}", look_up_type_id(*self).json_abi_str()) + format!( + "generic {}", + type_engine.look_up_type_id(*self).json_abi_str(type_engine) + ) } - _ => look_up_type_id(*self).json_abi_str(), + _ => type_engine.look_up_type_id(*self).json_abi_str(type_engine), } } } diff --git a/sway-core/src/type_system/type_info.rs b/sway-core/src/type_system/type_info.rs index a3a9412cda9..0aaa8253e4d 100644 --- a/sway-core/src/type_system/type_info.rs +++ b/sway-core/src/type_system/type_info.rs @@ -6,9 +6,8 @@ use crate::{ use sway_error::error::CompileError; use sway_types::{integer_bits::IntegerBits, span::Span}; -use derivative::Derivative; use std::{ - collections::{BTreeSet, HashSet}, + collections::HashSet, fmt, hash::{Hash, Hasher}, }; @@ -30,15 +29,48 @@ impl fmt::Display for AbiName { } } +/// A slow set primitive using `==` to check for containment. +#[derive(Clone)] +pub struct VecSet(pub Vec); + +impl fmt::Debug for VecSet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl core::ops::Deref for VecSet { + type Target = [T]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl VecSet { + pub fn is_subset(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.0.len() <= rhs.0.len() + && self + .0 + .iter() + .all(|x| rhs.0.iter().any(|y| x.eq(y, type_engine))) + } +} + +impl PartialEqWithTypeEngine for VecSet { + fn eq(&self, rhs: &Self, type_engine: &TypeEngine) -> bool { + self.is_subset(rhs, type_engine) && rhs.is_subset(self, type_engine) + } +} + /// Type information without an associated value, used for type inferencing and definition. // TODO use idents instead of Strings when we have arena spans -#[derive(Derivative)] -#[derivative(Debug, Clone)] +#[derive(Debug, Clone)] pub enum TypeInfo { Unknown, UnknownGeneric { name: Ident, - trait_constraints: BTreeSet, + // NOTE(Centril): Used to be BTreeSet; need to revert back later. Must be sorted! + trait_constraints: VecSet, }, Str(u64), UnsignedInteger(IntegerBits), @@ -100,8 +132,8 @@ pub enum TypeInfo { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl Hash for TypeInfo { - fn hash(&self, state: &mut H) { +impl HashWithTypeEngine for TypeInfo { + fn hash(&self, state: &mut H, type_engine: &TypeEngine) { match self { TypeInfo::Str(len) => { state.write_u8(1); @@ -119,7 +151,7 @@ impl Hash for TypeInfo { } TypeInfo::Tuple(fields) => { state.write_u8(5); - fields.hash(state); + fields.hash(state, type_engine); } TypeInfo::B256 => { state.write_u8(6); @@ -131,8 +163,8 @@ impl Hash for TypeInfo { } => { state.write_u8(7); name.hash(state); - variant_types.hash(state); - type_parameters.hash(state); + variant_types.hash(state, type_engine); + type_parameters.hash(state, type_engine); } TypeInfo::Struct { name, @@ -141,8 +173,8 @@ impl Hash for TypeInfo { } => { state.write_u8(8); name.hash(state); - fields.hash(state); - type_parameters.hash(state); + fields.hash(state, type_engine); + type_parameters.hash(state, type_engine); } TypeInfo::ContractCaller { abi_name, address } => { state.write_u8(9); @@ -171,7 +203,7 @@ impl Hash for TypeInfo { } => { state.write_u8(14); name.hash(state); - trait_constraints.hash(state); + trait_constraints.hash(state, type_engine); } TypeInfo::Custom { name, @@ -179,15 +211,17 @@ impl Hash for TypeInfo { } => { state.write_u8(15); name.hash(state); - type_arguments.hash(state); + type_arguments.as_deref().hash(state, type_engine); } TypeInfo::Storage { fields } => { state.write_u8(16); - fields.hash(state); + fields.hash(state, type_engine); } TypeInfo::Array(elem_ty, count, _) => { state.write_u8(17); - look_up_type_id(*elem_ty).hash(state); + type_engine + .look_up_type_id(*elem_ty) + .hash(state, type_engine); count.hash(state); } TypeInfo::RawUntypedPtr => { @@ -203,16 +237,17 @@ impl Hash for TypeInfo { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TypeInfo { - fn eq(&self, other: &Self) -> bool { +impl EqWithTypeEngine for TypeInfo {} +impl PartialEqWithTypeEngine for TypeInfo { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { match (self, other) { - (Self::Unknown, Self::Unknown) => true, - (Self::Boolean, Self::Boolean) => true, - (Self::SelfType, Self::SelfType) => true, - (Self::B256, Self::B256) => true, - (Self::Numeric, Self::Numeric) => true, - (Self::Contract, Self::Contract) => true, - (Self::ErrorRecovery, Self::ErrorRecovery) => true, + (Self::Unknown, Self::Unknown) + | (Self::Boolean, Self::Boolean) + | (Self::SelfType, Self::SelfType) + | (Self::B256, Self::B256) + | (Self::Numeric, Self::Numeric) + | (Self::Contract, Self::Contract) + | (Self::ErrorRecovery, Self::ErrorRecovery) => true, ( Self::UnknownGeneric { name: l, @@ -222,7 +257,7 @@ impl PartialEq for TypeInfo { name: r, trait_constraints: rtc, }, - ) => l == r && ltc == rtc, + ) => l == r && ltc.eq(rtc, type_engine), ( Self::Custom { name: l_name, @@ -232,7 +267,12 @@ impl PartialEq for TypeInfo { name: r_name, type_arguments: r_type_args, }, - ) => l_name == r_name && l_type_args == r_type_args, + ) => { + l_name == r_name + && l_type_args + .as_deref() + .eq(&r_type_args.as_deref(), type_engine) + } (Self::Str(l), Self::Str(r)) => l == r, (Self::UnsignedInteger(l), Self::UnsignedInteger(r)) => l == r, ( @@ -248,8 +288,8 @@ impl PartialEq for TypeInfo { }, ) => { l_name == r_name - && l_variant_types == r_variant_types - && l_type_parameters == r_type_parameters + && l_variant_types.eq(r_variant_types, type_engine) + && l_type_parameters.eq(r_type_parameters, type_engine) } ( Self::Struct { @@ -262,11 +302,19 @@ impl PartialEq for TypeInfo { fields: r_fields, type_parameters: r_type_parameters, }, - ) => l_name == r_name && l_fields == r_fields && l_type_parameters == r_type_parameters, + ) => { + l_name == r_name + && l_fields.eq(r_fields, type_engine) + && l_type_parameters.eq(r_type_parameters, type_engine) + } (Self::Tuple(l), Self::Tuple(r)) => l .iter() .zip(r.iter()) - .map(|(l, r)| look_up_type_id(l.type_id) == look_up_type_id(r.type_id)) + .map(|(l, r)| { + type_engine + .look_up_type_id(l.type_id) + .eq(&type_engine.look_up_type_id(r.type_id), type_engine) + }) .all(|x| x), ( Self::ContractCaller { @@ -277,12 +325,18 @@ impl PartialEq for TypeInfo { abi_name: r_abi_name, address: r_address, }, - ) => l_abi_name == r_abi_name && l_address == r_address, + ) => { + l_abi_name == r_abi_name + && l_address.as_deref().eq(&r_address.as_deref(), type_engine) + } (Self::Array(l0, l1, _), Self::Array(r0, r1, _)) => { - look_up_type_id(*l0) == look_up_type_id(*r0) && l1 == r1 + type_engine + .look_up_type_id(*l0) + .eq(&type_engine.look_up_type_id(*r0), type_engine) + && l1 == r1 } (TypeInfo::Storage { fields: l_fields }, TypeInfo::Storage { fields: r_fields }) => { - l_fields == r_fields + l_fields.eq(r_fields, type_engine) } (TypeInfo::RawUntypedPtr, TypeInfo::RawUntypedPtr) => true, (TypeInfo::RawUntypedSlice, TypeInfo::RawUntypedSlice) => true, @@ -291,16 +345,14 @@ impl PartialEq for TypeInfo { } } -impl Eq for TypeInfo {} - impl Default for TypeInfo { fn default() -> Self { TypeInfo::Unknown } } -impl fmt::Display for TypeInfo { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl DisplayWithTypeEngine for TypeInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { use TypeInfo::*; let s = match self { Unknown => "unknown".into(), @@ -318,7 +370,7 @@ impl fmt::Display for TypeInfo { Tuple(fields) => { let field_strs = fields .iter() - .map(|field| field.to_string()) + .map(|field| type_engine.help_out(field).to_string()) .collect::>(); format!("({})", field_strs.join(", ")) } @@ -332,6 +384,7 @@ impl fmt::Display for TypeInfo { type_parameters, .. } => print_inner_types( + type_engine, name.as_str().to_string(), type_parameters.iter().map(|x| x.type_id), ), @@ -340,6 +393,7 @@ impl fmt::Display for TypeInfo { type_parameters, .. } => print_inner_types( + type_engine, name.as_str().to_string(), type_parameters.iter().map(|x| x.type_id), ), @@ -353,7 +407,7 @@ impl fmt::Display for TypeInfo { .unwrap_or_else(|| "None".into()) ) } - Array(elem_ty, count, _) => format!("[{}; {}]", elem_ty, count), + Array(elem_ty, count, _) => format!("[{}; {}]", type_engine.help_out(elem_ty), count), Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), @@ -363,20 +417,24 @@ impl fmt::Display for TypeInfo { } impl UnconstrainedTypeParameters for TypeInfo { - fn type_parameter_is_unconstrained(&self, type_parameter: &TypeParameter) -> bool { - let type_parameter_info = look_up_type_id(type_parameter.type_id); + fn type_parameter_is_unconstrained( + &self, + type_engine: &TypeEngine, + type_parameter: &TypeParameter, + ) -> bool { + let type_parameter_info = type_engine.look_up_type_id(type_parameter.type_id); match self { TypeInfo::UnknownGeneric { trait_constraints, .. } => { - self.clone() == type_parameter_info + self.eq(&type_parameter_info, type_engine) || trait_constraints .iter() .flat_map(|trait_constraint| { trait_constraint.type_arguments.iter().map(|type_arg| { type_arg .type_id - .type_parameter_is_unconstrained(type_parameter) + .type_parameter_is_unconstrained(type_engine, type_parameter) }) }) .any(|x| x) @@ -391,7 +449,7 @@ impl UnconstrainedTypeParameters for TypeInfo { .map(|type_param| { type_param .type_id - .type_parameter_is_unconstrained(type_parameter) + .type_parameter_is_unconstrained(type_engine, type_parameter) }) .any(|x| x); let unconstrained_in_variants = variant_types @@ -399,7 +457,7 @@ impl UnconstrainedTypeParameters for TypeInfo { .map(|variant| { variant .type_id - .type_parameter_is_unconstrained(type_parameter) + .type_parameter_is_unconstrained(type_engine, type_parameter) }) .any(|x| x); unconstrained_in_type_parameters || unconstrained_in_variants @@ -414,7 +472,7 @@ impl UnconstrainedTypeParameters for TypeInfo { .map(|type_param| { type_param .type_id - .type_parameter_is_unconstrained(type_parameter) + .type_parameter_is_unconstrained(type_engine, type_parameter) }) .any(|x| x); let unconstrained_in_fields = fields @@ -422,14 +480,17 @@ impl UnconstrainedTypeParameters for TypeInfo { .map(|field| { field .type_id - .type_parameter_is_unconstrained(type_parameter) + .type_parameter_is_unconstrained(type_engine, type_parameter) }) .any(|x| x); unconstrained_in_type_parameters || unconstrained_in_fields } TypeInfo::Tuple(elems) => elems .iter() - .map(|elem| elem.type_id.type_parameter_is_unconstrained(type_parameter)) + .map(|elem| { + elem.type_id + .type_parameter_is_unconstrained(type_engine, type_parameter) + }) .any(|x| x), TypeInfo::Custom { type_arguments, .. } => type_arguments .clone() @@ -438,10 +499,12 @@ impl UnconstrainedTypeParameters for TypeInfo { .map(|type_arg| { type_arg .type_id - .type_parameter_is_unconstrained(type_parameter) + .type_parameter_is_unconstrained(type_engine, type_parameter) }) .any(|x| x), - TypeInfo::Array(elem, _, _) => elem.type_parameter_is_unconstrained(type_parameter), + TypeInfo::Array(elem, _, _) => { + elem.type_parameter_is_unconstrained(type_engine, type_parameter) + } TypeInfo::Unknown | TypeInfo::Str(_) | TypeInfo::UnsignedInteger(_) @@ -460,7 +523,7 @@ impl UnconstrainedTypeParameters for TypeInfo { } impl TypeInfo { - pub fn json_abi_str(&self) -> String { + pub fn json_abi_str(&self, type_engine: &TypeEngine) -> String { use TypeInfo::*; match self { Unknown => "unknown".into(), @@ -478,7 +541,7 @@ impl TypeInfo { Tuple(fields) => { let field_strs = fields .iter() - .map(|field| field.json_abi_str()) + .map(|field| field.json_abi_str(type_engine)) .collect::>(); format!("({})", field_strs.join(", ")) } @@ -496,7 +559,9 @@ impl TypeInfo { ContractCaller { abi_name, .. } => { format!("contract caller {}", abi_name) } - Array(elem_ty, count, _) => format!("[{}; {}]", elem_ty.json_abi_str(), count), + Array(elem_ty, count, _) => { + format!("[{}; {}]", elem_ty.json_abi_str(type_engine), count) + } Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), @@ -504,7 +569,11 @@ impl TypeInfo { } /// maps a type to a name that is used when constructing function selectors - pub(crate) fn to_selector_name(&self, error_msg_span: &Span) -> CompileResult { + pub(crate) fn to_selector_name( + &self, + type_engine: &TypeEngine, + error_msg_span: &Span, + ) -> CompileResult { use TypeInfo::*; let name = match self { Str(len) => format!("str[{}]", len), @@ -525,9 +594,10 @@ impl TypeInfo { let names = fields .iter() .map(|field_type| { - to_typeinfo(field_type.type_id, error_msg_span) + type_engine + .to_typeinfo(field_type.type_id, error_msg_span) .expect("unreachable?") - .to_selector_name(error_msg_span) + .to_selector_name(type_engine, error_msg_span) }) .collect::>>(); let mut buf = vec![]; @@ -552,11 +622,11 @@ impl TypeInfo { let names = fields .iter() .map(|ty| { - let ty = match to_typeinfo(ty.type_id, error_msg_span) { + let ty = match type_engine.to_typeinfo(ty.type_id, error_msg_span) { Err(e) => return err(vec![], vec![e.into()]), Ok(ty) => ty, }; - ty.to_selector_name(error_msg_span) + ty.to_selector_name(type_engine, error_msg_span) }) .collect::>>(); let mut buf = vec![]; @@ -573,11 +643,11 @@ impl TypeInfo { let type_arguments = type_parameters .iter() .map(|ty| { - let ty = match to_typeinfo(ty.type_id, error_msg_span) { + let ty = match type_engine.to_typeinfo(ty.type_id, error_msg_span) { Err(e) => return err(vec![], vec![e.into()]), Ok(ty) => ty, }; - ty.to_selector_name(error_msg_span) + ty.to_selector_name(type_engine, error_msg_span) }) .collect::>>(); let mut buf = vec![]; @@ -605,11 +675,11 @@ impl TypeInfo { let names = variant_types .iter() .map(|ty| { - let ty = match to_typeinfo(ty.type_id, error_msg_span) { + let ty = match type_engine.to_typeinfo(ty.type_id, error_msg_span) { Err(e) => return err(vec![], vec![e.into()]), Ok(ty) => ty, }; - ty.to_selector_name(error_msg_span) + ty.to_selector_name(type_engine, error_msg_span) }) .collect::>>(); let mut buf = vec![]; @@ -626,11 +696,11 @@ impl TypeInfo { let type_arguments = type_parameters .iter() .map(|ty| { - let ty = match to_typeinfo(ty.type_id, error_msg_span) { + let ty = match type_engine.to_typeinfo(ty.type_id, error_msg_span) { Err(e) => return err(vec![], vec![e.into()]), Ok(ty) => ty, }; - ty.to_selector_name(error_msg_span) + ty.to_selector_name(type_engine, error_msg_span) }) .collect::>>(); let mut buf = vec![]; @@ -653,7 +723,9 @@ impl TypeInfo { } } Array(type_id, size, _) => { - let name = look_up_type_id(*type_id).to_selector_name(error_msg_span); + let name = type_engine + .look_up_type_id(*type_id) + .to_selector_name(type_engine, error_msg_span); let name = match name.value { Some(name) => name, None => return name, @@ -674,34 +746,34 @@ impl TypeInfo { ok(name, vec![], vec![]) } - pub fn is_uninhabited(&self) -> bool { + pub fn is_uninhabited(&self, type_engine: &TypeEngine) -> bool { + let id_uninhabited = |id| type_engine.look_up_type_id(id).is_uninhabited(type_engine); + match self { TypeInfo::Enum { variant_types, .. } => variant_types .iter() - .all(|variant_type| look_up_type_id(variant_type.type_id).is_uninhabited()), - TypeInfo::Struct { fields, .. } => fields - .iter() - .any(|field| look_up_type_id(field.type_id).is_uninhabited()), + .all(|variant_type| id_uninhabited(variant_type.type_id)), + TypeInfo::Struct { fields, .. } => { + fields.iter().any(|field| id_uninhabited(field.type_id)) + } TypeInfo::Tuple(fields) => fields .iter() - .any(|field_type| look_up_type_id(field_type.type_id).is_uninhabited()), - TypeInfo::Array(type_id, size, _) => { - *size > 0 && look_up_type_id(*type_id).is_uninhabited() - } + .any(|field_type| id_uninhabited(field_type.type_id)), + TypeInfo::Array(type_id, size, _) => *size > 0 && id_uninhabited(*type_id), _ => false, } } - pub fn is_zero_sized(&self) -> bool { + pub fn is_zero_sized(&self, type_engine: &TypeEngine) -> bool { match self { TypeInfo::Enum { variant_types, .. } => { let mut found_unit_variant = false; for variant_type in variant_types { - let type_info = look_up_type_id(variant_type.type_id); - if type_info.is_uninhabited() { + let type_info = type_engine.look_up_type_id(variant_type.type_id); + if type_info.is_uninhabited(type_engine) { continue; } - if type_info.is_zero_sized() && !found_unit_variant { + if type_info.is_zero_sized(type_engine) && !found_unit_variant { found_unit_variant = true; continue; } @@ -712,11 +784,11 @@ impl TypeInfo { TypeInfo::Struct { fields, .. } => { let mut all_zero_sized = true; for field in fields { - let type_info = look_up_type_id(field.type_id); - if type_info.is_uninhabited() { + let type_info = type_engine.look_up_type_id(field.type_id); + if type_info.is_uninhabited(type_engine) { return true; } - if !type_info.is_zero_sized() { + if !type_info.is_zero_sized(type_engine) { all_zero_sized = false; } } @@ -725,33 +797,41 @@ impl TypeInfo { TypeInfo::Tuple(fields) => { let mut all_zero_sized = true; for field in fields { - let field_type = look_up_type_id(field.type_id); - if field_type.is_uninhabited() { + let field_type = type_engine.look_up_type_id(field.type_id); + if field_type.is_uninhabited(type_engine) { return true; } - if !field_type.is_zero_sized() { + if !field_type.is_zero_sized(type_engine) { all_zero_sized = false; } } all_zero_sized } TypeInfo::Array(type_id, size, _) => { - *size == 0 || look_up_type_id(*type_id).is_zero_sized() + *size == 0 + || type_engine + .look_up_type_id(*type_id) + .is_zero_sized(type_engine) } _ => false, } } - pub fn can_safely_ignore(&self) -> bool { - if self.is_zero_sized() { + pub fn can_safely_ignore(&self, type_engine: &TypeEngine) -> bool { + if self.is_zero_sized(type_engine) { return true; } match self { - TypeInfo::Tuple(fields) => fields - .iter() - .all(|type_argument| look_up_type_id(type_argument.type_id).can_safely_ignore()), + TypeInfo::Tuple(fields) => fields.iter().all(|type_argument| { + type_engine + .look_up_type_id(type_argument.type_id) + .can_safely_ignore(type_engine) + }), TypeInfo::Array(type_id, size, _) => { - *size == 0 || look_up_type_id(*type_id).can_safely_ignore() + *size == 0 + || type_engine + .look_up_type_id(*type_id) + .can_safely_ignore(type_engine) } TypeInfo::ErrorRecovery => true, TypeInfo::Unknown => true, @@ -827,10 +907,10 @@ impl TypeInfo { /// Given a `TypeInfo` `self`, analyze `self` and return all inner /// `TypeId`'s of `self`, not including `self`. - pub(crate) fn extract_inner_types(&self) -> HashSet { - fn helper(type_id: TypeId) -> HashSet { + pub(crate) fn extract_inner_types(&self, type_engine: &TypeEngine) -> HashSet { + let helper = |type_id: TypeId| { let mut inner_types = HashSet::new(); - match look_up_type_id(type_id) { + match type_engine.look_up_type_id(type_id) { TypeInfo::Enum { type_parameters, variant_types, @@ -838,11 +918,18 @@ impl TypeInfo { } => { inner_types.insert(type_id); for type_param in type_parameters.iter() { - inner_types - .extend(look_up_type_id(type_param.type_id).extract_inner_types()); + inner_types.extend( + type_engine + .look_up_type_id(type_param.type_id) + .extract_inner_types(type_engine), + ); } for variant in variant_types.iter() { - inner_types.extend(look_up_type_id(variant.type_id).extract_inner_types()); + inner_types.extend( + type_engine + .look_up_type_id(variant.type_id) + .extract_inner_types(type_engine), + ); } } TypeInfo::Struct { @@ -852,36 +939,58 @@ impl TypeInfo { } => { inner_types.insert(type_id); for type_param in type_parameters.iter() { - inner_types - .extend(look_up_type_id(type_param.type_id).extract_inner_types()); + inner_types.extend( + type_engine + .look_up_type_id(type_param.type_id) + .extract_inner_types(type_engine), + ); } for field in fields.iter() { - inner_types.extend(look_up_type_id(field.type_id).extract_inner_types()); + inner_types.extend( + type_engine + .look_up_type_id(field.type_id) + .extract_inner_types(type_engine), + ); } } TypeInfo::Custom { type_arguments, .. } => { inner_types.insert(type_id); if let Some(type_arguments) = type_arguments { for type_arg in type_arguments.iter() { - inner_types - .extend(look_up_type_id(type_arg.type_id).extract_inner_types()); + inner_types.extend( + type_engine + .look_up_type_id(type_arg.type_id) + .extract_inner_types(type_engine), + ); } } } TypeInfo::Array(type_id, _, _) => { inner_types.insert(type_id); - inner_types.extend(look_up_type_id(type_id).extract_inner_types()); + inner_types.extend( + type_engine + .look_up_type_id(type_id) + .extract_inner_types(type_engine), + ); } TypeInfo::Tuple(elems) => { inner_types.insert(type_id); for elem in elems.iter() { - inner_types.extend(look_up_type_id(elem.type_id).extract_inner_types()); + inner_types.extend( + type_engine + .look_up_type_id(elem.type_id) + .extract_inner_types(type_engine), + ); } } TypeInfo::Storage { fields } => { inner_types.insert(type_id); for field in fields.iter() { - inner_types.extend(look_up_type_id(field.type_id).extract_inner_types()); + inner_types.extend( + type_engine + .look_up_type_id(field.type_id) + .extract_inner_types(type_engine), + ); } } TypeInfo::Unknown @@ -901,7 +1010,7 @@ impl TypeInfo { TypeInfo::ErrorRecovery => {} } inner_types - } + }; let mut inner_types = HashSet::new(); match self { @@ -1039,7 +1148,11 @@ impl TypeInfo { /// Given a `TypeInfo` `self`, analyze `self` and return all nested /// `TypeInfo`'s found in `self`, including `self`. - pub(crate) fn extract_nested_types(self, span: &Span) -> CompileResult> { + pub(crate) fn extract_nested_types( + self, + type_engine: &TypeEngine, + span: &Span, + ) -> CompileResult> { let mut warnings = vec![]; let mut errors = vec![]; let mut all_nested_types = vec![self.clone()]; @@ -1051,7 +1164,9 @@ impl TypeInfo { } => { for type_parameter in type_parameters.iter() { let mut nested_types = check!( - look_up_type_id(type_parameter.type_id).extract_nested_types(span), + type_engine + .look_up_type_id(type_parameter.type_id) + .extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -1060,7 +1175,9 @@ impl TypeInfo { } for variant_type in variant_types.iter() { let mut nested_types = check!( - look_up_type_id(variant_type.type_id).extract_nested_types(span), + type_engine + .look_up_type_id(variant_type.type_id) + .extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -1075,7 +1192,9 @@ impl TypeInfo { } => { for type_parameter in type_parameters.iter() { let mut nested_types = check!( - look_up_type_id(type_parameter.type_id).extract_nested_types(span), + type_engine + .look_up_type_id(type_parameter.type_id) + .extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -1084,7 +1203,9 @@ impl TypeInfo { } for field in fields.iter() { let mut nested_types = check!( - look_up_type_id(field.type_id).extract_nested_types(span), + type_engine + .look_up_type_id(field.type_id) + .extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -1095,7 +1216,9 @@ impl TypeInfo { TypeInfo::Tuple(type_arguments) => { for type_argument in type_arguments.iter() { let mut nested_types = check!( - look_up_type_id(type_argument.type_id).extract_nested_types(span), + type_engine + .look_up_type_id(type_argument.type_id) + .extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -1105,7 +1228,9 @@ impl TypeInfo { } TypeInfo::Array(type_id, _, _) => { let mut nested_types = check!( - look_up_type_id(type_id).extract_nested_types(span), + type_engine + .look_up_type_id(type_id) + .extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -1115,7 +1240,9 @@ impl TypeInfo { TypeInfo::Storage { fields } => { for field in fields.iter() { let mut nested_types = check!( - look_up_type_id(field.type_id).extract_nested_types(span), + type_engine + .look_up_type_id(field.type_id) + .extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -1129,7 +1256,9 @@ impl TypeInfo { for trait_constraint in trait_constraints.iter() { for type_arg in trait_constraint.type_arguments.iter() { let mut nested_types = check!( - look_up_type_id(type_arg.type_id).extract_nested_types(span), + type_engine + .look_up_type_id(type_arg.type_id) + .extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -1160,11 +1289,15 @@ impl TypeInfo { ok(all_nested_types, warnings, errors) } - pub(crate) fn extract_nested_generics(&self, span: &Span) -> CompileResult> { + pub(crate) fn extract_nested_generics<'a>( + &self, + type_engine: &'a TypeEngine, + span: &Span, + ) -> CompileResult>> { let mut warnings = vec![]; let mut errors = vec![]; let nested_types = check!( - self.clone().extract_nested_types(span), + self.clone().extract_nested_types(type_engine, span), return err(warnings, errors), warnings, errors @@ -1172,7 +1305,11 @@ impl TypeInfo { let generics = HashSet::from_iter( nested_types .into_iter() - .filter(|x| matches!(x, TypeInfo::UnknownGeneric { .. })), + .filter(|x| matches!(x, TypeInfo::UnknownGeneric { .. })) + .map(|thing| WithTypeEngine { + thing, + engine: type_engine, + }), ); ok(generics, warnings, errors) } @@ -1252,7 +1389,7 @@ impl TypeInfo { /// constraints---if the trait constraints of `other` are a subset of the /// trait constraints of `self`, then we know that `other` has unique /// methods. - pub(crate) fn is_subset_of(&self, other: &TypeInfo) -> bool { + pub(crate) fn is_subset_of(&self, other: &TypeInfo, type_engine: &TypeEngine) -> bool { // handle the generics cases match (self, other) { ( @@ -1265,7 +1402,7 @@ impl TypeInfo { .. }, ) => { - return rtc.is_subset(ltc); + return rtc.is_subset(ltc, type_engine); } // any type is the subset of a generic (_, Self::UnknownGeneric { .. }) => { @@ -1274,20 +1411,27 @@ impl TypeInfo { _ => {} } - self.is_subset_inner(other) + self.is_subset_inner(other, type_engine) } /// Given two `TypeInfo`'s `self` and `other`, checks to see if `self` is /// unidirectionally a subset of `other`, excluding consideration of generic /// types (like in the `is_subset_of` method). - pub(crate) fn is_subset_of_for_item_import(&self, other: &TypeInfo) -> bool { - self.is_subset_inner(other) + pub(crate) fn is_subset_of_for_item_import( + &self, + other: &TypeInfo, + type_engine: &TypeEngine, + ) -> bool { + self.is_subset_inner(other, type_engine) } - fn is_subset_inner(&self, other: &TypeInfo) -> bool { + fn is_subset_inner(&self, other: &TypeInfo, type_engine: &TypeEngine) -> bool { match (self, other) { (Self::Array(l0, l1, _), Self::Array(r0, r1, _)) => { - look_up_type_id(*l0).is_subset_of(&look_up_type_id(*r0)) && l1 == r1 + type_engine + .look_up_type_id(*l0) + .is_subset_of(&type_engine.look_up_type_id(*r0), type_engine) + && l1 == r1 } ( Self::Custom { @@ -1303,15 +1447,15 @@ impl TypeInfo { .as_ref() .unwrap_or(&vec![]) .iter() - .map(|x| look_up_type_id(x.type_id)) + .map(|x| type_engine.look_up_type_id(x.type_id)) .collect::>(); let r_types = r_type_args .as_ref() .unwrap_or(&vec![]) .iter() - .map(|x| look_up_type_id(x.type_id)) + .map(|x| type_engine.look_up_type_id(x.type_id)) .collect::>(); - l_name == r_name && types_are_subset_of(&l_types, &r_types) + l_name == r_name && types_are_subset_of(type_engine, &l_types, &r_types) } ( Self::Enum { @@ -1335,13 +1479,15 @@ impl TypeInfo { .collect::>(); let l_types = l_type_parameters .iter() - .map(|x| look_up_type_id(x.type_id)) + .map(|x| type_engine.look_up_type_id(x.type_id)) .collect::>(); let r_types = r_type_parameters .iter() - .map(|x| look_up_type_id(x.type_id)) + .map(|x| type_engine.look_up_type_id(x.type_id)) .collect::>(); - l_name == r_name && l_names == r_names && types_are_subset_of(&l_types, &r_types) + l_name == r_name + && l_names == r_names + && types_are_subset_of(type_engine, &l_types, &r_types) } ( Self::Struct { @@ -1359,26 +1505,28 @@ impl TypeInfo { let r_names = r_fields.iter().map(|x| x.name.clone()).collect::>(); let l_types = l_type_parameters .iter() - .map(|x| look_up_type_id(x.type_id)) + .map(|x| type_engine.look_up_type_id(x.type_id)) .collect::>(); let r_types = r_type_parameters .iter() - .map(|x| look_up_type_id(x.type_id)) + .map(|x| type_engine.look_up_type_id(x.type_id)) .collect::>(); - l_name == r_name && l_names == r_names && types_are_subset_of(&l_types, &r_types) + l_name == r_name + && l_names == r_names + && types_are_subset_of(type_engine, &l_types, &r_types) } (Self::Tuple(l_types), Self::Tuple(r_types)) => { let l_types = l_types .iter() - .map(|x| look_up_type_id(x.type_id)) + .map(|x| type_engine.look_up_type_id(x.type_id)) .collect::>(); let r_types = r_types .iter() - .map(|x| look_up_type_id(x.type_id)) + .map(|x| type_engine.look_up_type_id(x.type_id)) .collect::>(); - types_are_subset_of(&l_types, &r_types) + types_are_subset_of(type_engine, &l_types, &r_types) } - (a, b) => a == b, + (a, b) => a.eq(b, type_engine), } } @@ -1395,6 +1543,7 @@ impl TypeInfo { /// 3) in the case where a `subfield` does not exist on `self` pub(crate) fn apply_subfields( &self, + type_engine: &TypeEngine, subfields: &[Ident], span: &Span, ) -> CompileResult { @@ -1424,7 +1573,11 @@ impl TypeInfo { field } else { check!( - look_up_type_id(field.type_id).apply_subfields(rest, span), + type_engine.look_up_type_id(field.type_id).apply_subfields( + type_engine, + rest, + span + ), return err(warnings, errors), warnings, errors @@ -1438,7 +1591,7 @@ impl TypeInfo { } (type_info, _) => { errors.push(CompileError::FieldAccessOnNonStruct { - actually: type_info.to_string(), + actually: type_engine.help_out(type_info).to_string(), span: span.clone(), }); err(warnings, errors) @@ -1482,6 +1635,7 @@ impl TypeInfo { /// Returns an error if `self` is not a `TypeInfo::Tuple`. pub(crate) fn expect_tuple( &self, + type_engine: &TypeEngine, debug_string: impl Into, debug_span: &Span, ) -> CompileResult<&Vec> { @@ -1495,7 +1649,7 @@ impl TypeInfo { vec![CompileError::NotATuple { name: debug_string.into(), span: debug_span.clone(), - actually: a.to_string(), + actually: type_engine.help_out(a).to_string(), }], ), } @@ -1507,6 +1661,7 @@ impl TypeInfo { /// Returns an error if `self` is not a `TypeInfo::Enum`. pub(crate) fn expect_enum( &self, + type_engine: &TypeEngine, debug_string: impl Into, debug_span: &Span, ) -> CompileResult<(&Ident, &Vec)> { @@ -1524,7 +1679,7 @@ impl TypeInfo { vec![CompileError::NotAnEnum { name: debug_string.into(), span: debug_span.clone(), - actually: a.to_string(), + actually: type_engine.help_out(a).to_string(), }], ), } @@ -1537,6 +1692,7 @@ impl TypeInfo { #[allow(dead_code)] pub(crate) fn expect_struct( &self, + type_engine: &TypeEngine, debug_span: &Span, ) -> CompileResult<(&Ident, &Vec)> { let warnings = vec![]; @@ -1548,7 +1704,7 @@ impl TypeInfo { vec![], vec![CompileError::NotAStruct { span: debug_span.clone(), - actually: a.to_string(), + actually: type_engine.help_out(a).to_string(), }], ), } @@ -1620,7 +1776,7 @@ impl TypeInfo { /// /// `left` is a subset of `right`. /// -fn types_are_subset_of(left: &[TypeInfo], right: &[TypeInfo]) -> bool { +fn types_are_subset_of(type_engine: &TypeEngine, left: &[TypeInfo], right: &[TypeInfo]) -> bool { // invariant 1. `left` and and `right` are of the same length _n_ if left.len() != right.len() { return false; @@ -1633,7 +1789,7 @@ fn types_are_subset_of(left: &[TypeInfo], right: &[TypeInfo]) -> bool { // invariant 2. For every _i_ in [0, n), `left`áµ¢ is a subset of `right`áµ¢ for (l, r) in left.iter().zip(right.iter()) { - if !l.is_subset_of(r) { + if !l.is_subset_of(r, type_engine) { return false; } } @@ -1644,7 +1800,7 @@ fn types_are_subset_of(left: &[TypeInfo], right: &[TypeInfo]) -> bool { for j in (i + 1)..right.len() { let a = right.get(i).unwrap(); let b = right.get(j).unwrap(); - if a == b { + if a.eq(b, type_engine) { // if a and b are the same type constraints.push((i, j)); } @@ -1653,7 +1809,7 @@ fn types_are_subset_of(left: &[TypeInfo], right: &[TypeInfo]) -> bool { for (i, j) in constraints.into_iter() { let a = left.get(i).unwrap(); let b = left.get(j).unwrap(); - if a != b { + if !a.eq(b, type_engine) { return false; } } @@ -1662,8 +1818,14 @@ fn types_are_subset_of(left: &[TypeInfo], right: &[TypeInfo]) -> bool { true } -fn print_inner_types(name: String, inner_types: impl Iterator) -> String { - let inner_types = inner_types.map(|x| x.to_string()).collect::>(); +fn print_inner_types( + type_engine: &TypeEngine, + name: String, + inner_types: impl Iterator, +) -> String { + let inner_types = inner_types + .map(|x| type_engine.help_out(x).to_string()) + .collect::>(); format!( "{}{}", name, diff --git a/sway-core/src/type_system/type_mapping.rs b/sway-core/src/type_system/type_mapping.rs index 8d3fd81cffe..4cb0e44a5a8 100644 --- a/sway-core/src/type_system/type_mapping.rs +++ b/sway-core/src/type_system/type_mapping.rs @@ -11,14 +11,20 @@ pub(crate) struct TypeMapping { mapping: Vec<(SourceType, DestinationType)>, } -impl fmt::Display for TypeMapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl DisplayWithTypeEngine for TypeMapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { write!( f, "TypeMapping {{ {} }}", self.mapping .iter() - .map(|(source_type, dest_type)| { format!("{} -> {}", source_type, dest_type) }) + .map(|(source_type, dest_type)| { + format!( + "{} -> {}", + type_engine.help_out(source_type), + type_engine.help_out(dest_type) + ) + }) .collect::>() .join(", ") ) @@ -49,15 +55,18 @@ impl TypeMapping { /// `type_parameters`. The [SourceType]s of the resulting [TypeMapping] are /// the [TypeId]s from `type_parameters` and the [DestinationType]s are the /// new [TypeId]s created from a transformation upon `type_parameters`. - pub(crate) fn from_type_parameters(type_parameters: &[TypeParameter]) -> TypeMapping { + pub(crate) fn from_type_parameters( + type_parameters: &[TypeParameter], + type_engine: &TypeEngine, + ) -> TypeMapping { let mapping = type_parameters .iter() .map(|x| { ( x.type_id, - insert_type(TypeInfo::UnknownGeneric { + type_engine.insert_type(TypeInfo::UnknownGeneric { name: x.name_ident.clone(), - trait_constraints: x.trait_constraints.clone().into_iter().collect(), + trait_constraints: VecSet(x.trait_constraints.clone()), }), ) }) @@ -112,8 +121,15 @@ impl TypeMapping { /// `subset`. This [TypeMapping] can be used to complete monomorphization on /// methods, etc, that are implemented for the type of `superset` so that /// they can be used for `subset`. - pub(crate) fn from_superset_and_subset(superset: TypeId, subset: TypeId) -> TypeMapping { - match (look_up_type_id(superset), look_up_type_id(subset)) { + pub(crate) fn from_superset_and_subset( + type_engine: &TypeEngine, + superset: TypeId, + subset: TypeId, + ) -> TypeMapping { + match ( + type_engine.look_up_type_id(superset), + type_engine.look_up_type_id(subset), + ) { (TypeInfo::UnknownGeneric { .. }, _) => TypeMapping { mapping: vec![(superset, subset)], }, @@ -257,11 +273,11 @@ impl TypeMapping { /// finds a match in a recursive call to `find_match` /// /// A match cannot be found in any other circumstance. - pub(crate) fn find_match(&self, type_id: TypeId) -> Option { - let type_info = look_up_type_id(type_id); + pub(crate) fn find_match(&self, type_id: TypeId, type_engine: &TypeEngine) -> Option { + let type_info = type_engine.look_up_type_id(type_id); match type_info { - TypeInfo::Custom { .. } => iter_for_match(self, &type_info), - TypeInfo::UnknownGeneric { .. } => iter_for_match(self, &type_info), + TypeInfo::Custom { .. } => iter_for_match(type_engine, self, &type_info), + TypeInfo::UnknownGeneric { .. } => iter_for_match(type_engine, self, &type_info), TypeInfo::Struct { fields, name, @@ -271,7 +287,7 @@ impl TypeMapping { let fields = fields .into_iter() .map(|mut field| { - if let Some(type_id) = self.find_match(field.type_id) { + if let Some(type_id) = self.find_match(field.type_id, type_engine) { need_to_create_new = true; field.type_id = type_id; } @@ -281,7 +297,7 @@ impl TypeMapping { let type_parameters = type_parameters .into_iter() .map(|mut type_param| { - if let Some(type_id) = self.find_match(type_param.type_id) { + if let Some(type_id) = self.find_match(type_param.type_id, type_engine) { need_to_create_new = true; type_param.type_id = type_id; } @@ -289,7 +305,7 @@ impl TypeMapping { }) .collect::>(); if need_to_create_new { - Some(insert_type(TypeInfo::Struct { + Some(type_engine.insert_type(TypeInfo::Struct { fields, name, type_parameters, @@ -307,7 +323,7 @@ impl TypeMapping { let variant_types = variant_types .into_iter() .map(|mut variant| { - if let Some(type_id) = self.find_match(variant.type_id) { + if let Some(type_id) = self.find_match(variant.type_id, type_engine) { need_to_create_new = true; variant.type_id = type_id; } @@ -317,7 +333,7 @@ impl TypeMapping { let type_parameters = type_parameters .into_iter() .map(|mut type_param| { - if let Some(type_id) = self.find_match(type_param.type_id) { + if let Some(type_id) = self.find_match(type_param.type_id, type_engine) { need_to_create_new = true; type_param.type_id = type_id; } @@ -325,7 +341,7 @@ impl TypeMapping { }) .collect::>(); if need_to_create_new { - Some(insert_type(TypeInfo::Enum { + Some(type_engine.insert_type(TypeInfo::Enum { variant_types, type_parameters, name, @@ -335,8 +351,8 @@ impl TypeMapping { } } TypeInfo::Array(ary_ty_id, count, initial_elem_ty) => { - self.find_match(ary_ty_id).map(|matching_id| { - insert_type(TypeInfo::Array(matching_id, count, initial_elem_ty)) + self.find_match(ary_ty_id, type_engine).map(|matching_id| { + type_engine.insert_type(TypeInfo::Array(matching_id, count, initial_elem_ty)) }) } TypeInfo::Tuple(fields) => { @@ -344,7 +360,7 @@ impl TypeMapping { let fields = fields .into_iter() .map(|mut field| { - if let Some(type_id) = self.find_match(field.type_id) { + if let Some(type_id) = self.find_match(field.type_id, type_engine) { need_to_create_new = true; field.type_id = type_id; } @@ -352,7 +368,7 @@ impl TypeMapping { }) .collect::>(); if need_to_create_new { - Some(insert_type(TypeInfo::Tuple(fields))) + Some(type_engine.insert_type(TypeInfo::Tuple(fields))) } else { None } @@ -362,7 +378,7 @@ impl TypeMapping { let fields = fields .into_iter() .map(|mut field| { - if let Some(type_id) = self.find_match(field.type_id) { + if let Some(type_id) = self.find_match(field.type_id, type_engine) { need_to_create_new = true; field.type_id = type_id; } @@ -370,7 +386,7 @@ impl TypeMapping { }) .collect::>(); if need_to_create_new { - Some(insert_type(TypeInfo::Storage { fields })) + Some(type_engine.insert_type(TypeInfo::Storage { fields })) } else { None } @@ -391,9 +407,16 @@ impl TypeMapping { } } -fn iter_for_match(type_mapping: &TypeMapping, type_info: &TypeInfo) -> Option { +fn iter_for_match( + type_engine: &TypeEngine, + type_mapping: &TypeMapping, + type_info: &TypeInfo, +) -> Option { for (source_type, dest_type) in type_mapping.mapping.iter() { - if look_up_type_id(*source_type) == *type_info { + if type_engine + .look_up_type_id(*source_type) + .eq(type_info, type_engine) + { return Some(*dest_type); } } diff --git a/sway-core/src/type_system/type_parameter.rs b/sway-core/src/type_system/type_parameter.rs index cee236e2e1e..61f412f4dcd 100644 --- a/sway-core/src/type_system/type_parameter.rs +++ b/sway-core/src/type_system/type_parameter.rs @@ -15,7 +15,7 @@ use std::{ hash::{Hash, Hasher}, }; -#[derive(Clone, Eq)] +#[derive(Clone)] pub struct TypeParameter { pub type_id: TypeId, pub(crate) initial_type_id: TypeId, @@ -27,40 +27,47 @@ pub struct TypeParameter { // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl Hash for TypeParameter { - fn hash(&self, state: &mut H) { - look_up_type_id(self.type_id).hash(state); +impl HashWithTypeEngine for TypeParameter { + fn hash(&self, state: &mut H, type_engine: &TypeEngine) { + type_engine + .look_up_type_id(self.type_id) + .hash(state, type_engine); self.name_ident.hash(state); - self.trait_constraints.hash(state); + self.trait_constraints.hash(state, type_engine); } } // NOTE: Hash and PartialEq must uphold the invariant: // k1 == k2 -> hash(k1) == hash(k2) // https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for TypeParameter { - fn eq(&self, other: &Self) -> bool { - look_up_type_id(self.type_id) == look_up_type_id(other.type_id) +impl EqWithTypeEngine for TypeParameter {} +impl PartialEqWithTypeEngine for TypeParameter { + fn eq(&self, other: &Self, type_engine: &TypeEngine) -> bool { + type_engine + .look_up_type_id(self.type_id) + .eq(&type_engine.look_up_type_id(other.type_id), type_engine) && self.name_ident == other.name_ident - && self.trait_constraints == other.trait_constraints + && self + .trait_constraints + .eq(&other.trait_constraints, type_engine) } } impl CopyTypes for TypeParameter { - fn copy_types_inner(&mut self, type_mapping: &TypeMapping) { - self.type_id.copy_types(type_mapping); + fn copy_types_inner(&mut self, type_mapping: &TypeMapping, type_engine: &TypeEngine) { + self.type_id.copy_types(type_mapping, type_engine); self.trait_constraints .iter_mut() - .for_each(|x| x.copy_types(type_mapping)); + .for_each(|x| x.copy_types(type_mapping, type_engine)); } } impl ReplaceSelfType for TypeParameter { - fn replace_self_type(&mut self, self_type: TypeId) { - self.type_id.replace_self_type(self_type); + fn replace_self_type(&mut self, type_engine: &TypeEngine, self_type: TypeId) { + self.type_id.replace_self_type(type_engine, self_type); self.trait_constraints .iter_mut() - .for_each(|x| x.replace_self_type(self_type)); + .for_each(|x| x.replace_self_type(type_engine, self_type)); } } @@ -70,9 +77,14 @@ impl Spanned for TypeParameter { } } -impl fmt::Display for TypeParameter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self.name_ident, self.type_id) +impl DisplayWithTypeEngine for TypeParameter { + fn fmt(&self, f: &mut fmt::Formatter<'_>, type_engine: &TypeEngine) -> fmt::Result { + write!( + f, + "{}: {}", + self.name_ident, + type_engine.help_out(self.type_id) + ) } } @@ -110,9 +122,9 @@ impl TypeParameter { // TODO: add check here to see if the type parameter has a valid name and does not have type parameters - let type_id = insert_type(TypeInfo::UnknownGeneric { + let type_id = ctx.type_engine.insert_type(TypeInfo::UnknownGeneric { name: name_ident.clone(), - trait_constraints: trait_constraints.clone().into_iter().collect(), + trait_constraints: VecSet(trait_constraints.clone()), }); // Insert the trait constraints into the namespace. @@ -147,17 +159,25 @@ impl TypeParameter { /// Returns the initial type ID of a TypeParameter. Also updates the provided list of types to /// append the current TypeParameter as a `JsonTypeDeclaration`. - pub(crate) fn get_json_type_parameter(&self, types: &mut Vec) -> usize { + pub(crate) fn get_json_type_parameter( + &self, + type_engine: &TypeEngine, + types: &mut Vec, + ) -> usize { let type_parameter = JsonTypeDeclaration { - type_id: *self.initial_type_id, - type_field: self.initial_type_id.get_json_type_str(self.type_id), - components: self + type_id: self.initial_type_id.index(), + type_field: self .initial_type_id - .get_json_type_components(types, self.type_id), + .get_json_type_str(type_engine, self.type_id), + components: self.initial_type_id.get_json_type_components( + type_engine, + types, + self.type_id, + ), type_parameters: None, }; types.push(type_parameter); - *self.initial_type_id + self.initial_type_id.index() } /// Creates a [DeclMapping] from a list of [TypeParameter]s. @@ -186,7 +206,8 @@ impl TypeParameter { .check_if_trait_constraints_are_satisfied_for_type( *type_id, trait_constraints, - access_span + access_span, + ctx.type_engine, ), continue, warnings, diff --git a/sway-core/src/type_system/unconstrained_type_parameters.rs b/sway-core/src/type_system/unconstrained_type_parameters.rs index 99c00704415..7c2543a53d9 100644 --- a/sway-core/src/type_system/unconstrained_type_parameters.rs +++ b/sway-core/src/type_system/unconstrained_type_parameters.rs @@ -1,15 +1,20 @@ -use crate::TypeParameter; +use crate::{TypeEngine, TypeParameter}; pub(crate) trait UnconstrainedTypeParameters { - fn type_parameter_is_unconstrained(&self, type_parameter: &TypeParameter) -> bool; + fn type_parameter_is_unconstrained( + &self, + type_engine: &TypeEngine, + type_parameter: &TypeParameter, + ) -> bool; fn unconstrained_type_parameters<'a>( &self, + type_engine: &TypeEngine, type_parameters: &'a [TypeParameter], ) -> Vec<&'a TypeParameter> { let mut unconstrained = vec![]; for type_param in type_parameters.iter() { - if self.type_parameter_is_unconstrained(type_param) { + if self.type_parameter_is_unconstrained(type_engine, type_param) { unconstrained.push(type_param); } } diff --git a/sway-core/src/type_system/unify.rs b/sway-core/src/type_system/unify.rs index 37f80fb63b3..2b21d00d6a0 100644 --- a/sway-core/src/type_system/unify.rs +++ b/sway-core/src/type_system/unify.rs @@ -30,8 +30,8 @@ pub(super) fn unify( }; match ( - type_engine.slab.get(*received), - type_engine.slab.get(*expected), + type_engine.slab.get(received.index()), + type_engine.slab.get(expected.index()), ) { // If they have the same `TypeInfo`, then we either compare them for // correctness or perform further unification. @@ -50,6 +50,7 @@ pub(super) fn unify( l, r, arguments_are_flipped, + type_engine, ), (Tuple(rfs), Tuple(efs)) if rfs.len() == efs.len() => { unify::unify_tuples(help_text, rfs, efs, curried) @@ -58,7 +59,7 @@ pub(super) fn unify( unify::unify_unsigned_ints(span, r, e, arguments_are_flipped) } (Numeric, e @ UnsignedInteger(_)) => { - match type_engine.slab.replace(received, &Numeric, e) { + match type_engine.slab.replace(received, &Numeric, e, type_engine) { None => (vec![], vec![]), Some(_) => unify( type_engine, @@ -71,7 +72,7 @@ pub(super) fn unify( } } (r @ UnsignedInteger(_), Numeric) => { - match type_engine.slab.replace(expected, &Numeric, r) { + match type_engine.slab.replace(expected, &Numeric, r, type_engine) { None => (vec![], vec![]), Some(_) => unify( type_engine, @@ -103,6 +104,7 @@ pub(super) fn unify( (en, etps, efs), curried, arguments_are_flipped, + type_engine, ), ( Enum { @@ -124,6 +126,7 @@ pub(super) fn unify( (en, etps, evs), curried, arguments_are_flipped, + type_engine, ), (Array(re, rc, _), Array(ee, ec, _)) if rc == ec => unify::unify_arrays( received, @@ -134,6 +137,7 @@ pub(super) fn unify( ee, curried, arguments_are_flipped, + type_engine, ), ( ref r @ TypeInfo::ContractCaller { @@ -145,10 +149,12 @@ pub(super) fn unify( }, ) if (ran == ean && rra.is_none()) || matches!(ran, AbiName::Deferred) => { // if one address is empty, coerce to the other one - match type_engine - .slab - .replace(received, r, type_engine.slab.get(*expected)) - { + match type_engine.slab.replace( + received, + r, + type_engine.slab.get(expected.index()), + type_engine, + ) { None => (vec![], vec![]), Some(_) => unify( type_engine, @@ -170,10 +176,12 @@ pub(super) fn unify( }, ) if (ran == ean && ea.is_none()) || matches!(ean, AbiName::Deferred) => { // if one address is empty, coerce to the other one - match type_engine - .slab - .replace(expected, e, type_engine.slab.get(*received)) - { + match type_engine.slab.replace( + expected, + e, + type_engine.slab.get(received.index()), + type_engine, + ) { None => (vec![], vec![]), Some(_) => unify( type_engine, @@ -186,7 +194,7 @@ pub(super) fn unify( } } (ref r @ TypeInfo::ContractCaller { .. }, ref e @ TypeInfo::ContractCaller { .. }) - if r == e => + if r.eq(e, type_engine) => { // if they are the same, then it's ok (vec![], vec![]) @@ -196,7 +204,7 @@ pub(super) fn unify( // they match and make the one we know nothing about reference the // one we may know something about (Unknown, Unknown) => (vec![], vec![]), - (Unknown, e) => match type_engine.slab.replace(received, &Unknown, e) { + (Unknown, e) => match type_engine.slab.replace(received, &Unknown, e, type_engine) { None => (vec![], vec![]), Some(_) => unify( type_engine, @@ -207,7 +215,7 @@ pub(super) fn unify( arguments_are_flipped, ), }, - (r, Unknown) => match type_engine.slab.replace(expected, &Unknown, r) { + (r, Unknown) => match type_engine.slab.replace(expected, &Unknown, r, type_engine) { None => (vec![], vec![]), Some(_) => unify( type_engine, @@ -228,38 +236,44 @@ pub(super) fn unify( name: en, trait_constraints: etc, }, - ) if rn.as_str() == en.as_str() && rtc == etc => (vec![], vec![]), - (ref r @ UnknownGeneric { .. }, e) => match type_engine.slab.replace(received, r, e) { - None => (vec![], vec![]), - Some(_) => unify( - type_engine, - received, - expected, - span, - help_text, - arguments_are_flipped, - ), - }, - (r, ref e @ UnknownGeneric { .. }) => match type_engine.slab.replace(expected, e, r) { - None => (vec![], vec![]), - Some(_) => unify( - type_engine, - received, - expected, - span, - help_text, - arguments_are_flipped, - ), - }, + ) if rn.as_str() == en.as_str() && rtc.eq(&etc, type_engine) => (vec![], vec![]), + (ref r @ UnknownGeneric { .. }, e) => { + match type_engine.slab.replace(received, r, e, type_engine) { + None => (vec![], vec![]), + Some(_) => unify( + type_engine, + received, + expected, + span, + help_text, + arguments_are_flipped, + ), + } + } + (r, ref e @ UnknownGeneric { .. }) => { + match type_engine.slab.replace(expected, e, r, type_engine) { + None => (vec![], vec![]), + Some(_) => unify( + type_engine, + received, + expected, + span, + help_text, + arguments_are_flipped, + ), + } + } // If no previous attempts to unify were successful, raise an error (TypeInfo::ErrorRecovery, _) => (vec![], vec![]), (_, TypeInfo::ErrorRecovery) => (vec![], vec![]), (r, e) => { + let e = type_engine.help_out(e).to_string(); + let r = type_engine.help_out(r).to_string(); let (expected, received) = if !arguments_are_flipped { - (e.to_string(), r.to_string()) + (e, r) } else { - (r.to_string(), e.to_string()) + (r, e) }; let errors = vec![TypeError::MismatchedType { expected, @@ -287,8 +301,8 @@ pub(super) fn unify_right( }; match ( - type_engine.slab.get(*received), - type_engine.slab.get(*expected), + type_engine.slab.get(received.index()), + type_engine.slab.get(expected.index()), ) { // If they have the same `TypeInfo`, then we either compare them for // correctness or perform further unification. @@ -299,14 +313,23 @@ pub(super) fn unify_right( (Contract, Contract) => (vec![], vec![]), (RawUntypedPtr, RawUntypedPtr) => (vec![], vec![]), (RawUntypedSlice, RawUntypedSlice) => (vec![], vec![]), - (Str(l), Str(r)) => unify::unify_strs(received, expected, span, help_text, l, r, false), + (Str(l), Str(r)) => unify::unify_strs( + received, + expected, + span, + help_text, + l, + r, + false, + type_engine, + ), (Tuple(rfs), Tuple(efs)) if rfs.len() == efs.len() => { unify::unify_tuples(help_text, rfs, efs, curried) } (UnsignedInteger(r), UnsignedInteger(e)) => unify::unify_unsigned_ints(span, r, e, false), (Numeric, UnsignedInteger(_)) => (vec![], vec![]), (r @ UnsignedInteger(_), Numeric) => { - match type_engine.slab.replace(expected, &Numeric, r) { + match type_engine.slab.replace(expected, &Numeric, r, type_engine) { None => (vec![], vec![]), Some(_) => unify_right(type_engine, received, expected, span, help_text), } @@ -331,6 +354,7 @@ pub(super) fn unify_right( (en, etps, efs), curried, false, + type_engine, ), ( Enum { @@ -352,10 +376,19 @@ pub(super) fn unify_right( (en, etps, evs), curried, false, + type_engine, + ), + (Array(re, rc, _), Array(ee, ec, _)) if rc == ec => unify::unify_arrays( + received, + expected, + span, + help_text, + re, + ee, + curried, + false, + type_engine, ), - (Array(re, rc, _), Array(ee, ec, _)) if rc == ec => { - unify::unify_arrays(received, expected, span, help_text, re, ee, curried, false) - } ( TypeInfo::ContractCaller { abi_name: ref ran, .. @@ -366,10 +399,12 @@ pub(super) fn unify_right( }, ) if (ran == ean && ea.is_none()) || matches!(ean, AbiName::Deferred) => { // if one address is empty, coerce to the other one - match type_engine - .slab - .replace(expected, e, type_engine.slab.get(*received)) - { + match type_engine.slab.replace( + expected, + e, + type_engine.slab.get(received.index()), + type_engine, + ) { None => (vec![], vec![]), Some(_) => unify_right(type_engine, received, expected, span, help_text), } @@ -384,7 +419,7 @@ pub(super) fn unify_right( }, ) if (ran == ean && ra.is_none()) || matches!(ran, AbiName::Deferred) => (vec![], vec![]), (ref r @ TypeInfo::ContractCaller { .. }, ref e @ TypeInfo::ContractCaller { .. }) - if r == e => + if r.eq(e, type_engine) => { // if they are the same, then it's ok (vec![], vec![]) @@ -394,7 +429,7 @@ pub(super) fn unify_right( // they match and make the one we know nothing about reference the // one we may know something about (Unknown, Unknown) => (vec![], vec![]), - (r, Unknown) => match type_engine.slab.replace(expected, &Unknown, r) { + (r, Unknown) => match type_engine.slab.replace(expected, &Unknown, r, type_engine) { None => (vec![], vec![]), Some(_) => unify_right(type_engine, received, expected, span, help_text), }, @@ -409,11 +444,13 @@ pub(super) fn unify_right( name: en, trait_constraints: etc, }, - ) if rn.as_str() == en.as_str() && rtc == etc => (vec![], vec![]), - (r, ref e @ UnknownGeneric { .. }) => match type_engine.slab.replace(expected, e, r) { - None => (vec![], vec![]), - Some(_) => unify_right(type_engine, received, expected, span, help_text), - }, + ) if rn.as_str() == en.as_str() && rtc.eq(&etc, type_engine) => (vec![], vec![]), + (r, ref e @ UnknownGeneric { .. }) => { + match type_engine.slab.replace(expected, e, r, type_engine) { + None => (vec![], vec![]), + Some(_) => unify_right(type_engine, received, expected, span, help_text), + } + } // this case is purposefully removed because it should cause an // error. trying to unify_right a generic with anything other an an // unknown or another generic is a type error @@ -424,8 +461,8 @@ pub(super) fn unify_right( (_, TypeInfo::ErrorRecovery) => (vec![], vec![]), (r, e) => { let errors = vec![TypeError::MismatchedType { - expected: e.to_string(), - received: r.to_string(), + expected: type_engine.help_out(e).to_string(), + received: type_engine.help_out(r).to_string(), help_text: help_text.to_string(), span: span.clone(), }]; @@ -434,6 +471,7 @@ pub(super) fn unify_right( } } +#[allow(clippy::too_many_arguments)] fn unify_strs( received: TypeId, expected: TypeId, @@ -442,14 +480,17 @@ fn unify_strs( r: u64, e: u64, arguments_are_flipped: bool, + type_engine: &TypeEngine, ) -> (Vec, Vec) { let warnings = vec![]; let mut errors = vec![]; if r != e { - let (expected, received) = if !arguments_are_flipped { - (expected.to_string(), received.to_string()) + let expected = type_engine.help_out(expected).to_string(); + let received = type_engine.help_out(received).to_string(); + let (expected, received) = if arguments_are_flipped { + (received, expected) } else { - (received.to_string(), expected.to_string()) + (expected, received) }; errors.push(TypeError::MismatchedType { expected, @@ -556,6 +597,7 @@ fn unify_structs( e: (Ident, Vec, Vec), unifier: F, arguments_are_flipped: bool, + type_engine: &TypeEngine, ) -> (Vec, Vec) where F: Fn(TypeId, TypeId, &Span, &str) -> (Vec, Vec), @@ -580,10 +622,12 @@ where ); }); } else { - let (expected, received) = if !arguments_are_flipped { - (expected.to_string(), received.to_string()) + let expected = type_engine.help_out(expected).to_string(); + let received = type_engine.help_out(received).to_string(); + let (expected, received) = if arguments_are_flipped { + (received, expected) } else { - (received.to_string(), expected.to_string()) + (expected, received) }; errors.push(TypeError::MismatchedType { expected, @@ -605,6 +649,7 @@ fn unify_enums( e: (Ident, Vec, Vec), unifier: F, arguments_are_flipped: bool, + type_engine: &TypeEngine, ) -> (Vec, Vec) where F: Fn(TypeId, TypeId, &Span, &str) -> (Vec, Vec), @@ -629,10 +674,12 @@ where ); }); } else { - let (expected, received) = if !arguments_are_flipped { - (expected.to_string(), received.to_string()) + let expected = type_engine.help_out(expected).to_string(); + let received = type_engine.help_out(received).to_string(); + let (expected, received) = if arguments_are_flipped { + (received, expected) } else { - (received.to_string(), expected.to_string()) + (expected, received) }; errors.push(TypeError::MismatchedType { expected, @@ -654,6 +701,7 @@ fn unify_arrays( e: TypeId, unifier: F, arguments_are_flipped: bool, + type_engine: &TypeEngine, ) -> (Vec, Vec) where F: Fn(TypeId, TypeId, &Span, &str) -> (Vec, Vec), @@ -664,10 +712,12 @@ where // the elem types. let mut errors = vec![]; if !new_errors.is_empty() { - let (expected, received) = if !arguments_are_flipped { - (expected.to_string(), received.to_string()) + let expected = type_engine.help_out(expected).to_string(); + let received = type_engine.help_out(received).to_string(); + let (expected, received) = if arguments_are_flipped { + (received, expected) } else { - (received.to_string(), expected.to_string()) + (expected, received) }; errors.push(TypeError::MismatchedType { expected, diff --git a/sway-lsp/src/capabilities/hover.rs b/sway-lsp/src/capabilities/hover.rs index 56a7db0bb78..df6e7c19d93 100644 --- a/sway-lsp/src/capabilities/hover.rs +++ b/sway-lsp/src/capabilities/hover.rs @@ -12,7 +12,7 @@ use std::sync::Arc; use sway_core::{ declaration_engine, language::{ty, Visibility}, - TypeId, + TypeEngine, TypeId, }; use sway_types::{Ident, Span, Spanned}; use tower_lsp::lsp_types::{self, Position, Url}; @@ -34,7 +34,7 @@ pub fn hover_data(session: Arc, url: Url, position: Position) -> Option None => (ident, token), }; - let contents = hover_format(&decl_token, &decl_ident); + let contents = hover_format(&session.type_engine.read(), &decl_token, &decl_ident); Some(lsp_types::Hover { contents, range: Some(range), @@ -91,12 +91,16 @@ fn markup_content(markup: Markup) -> lsp_types::MarkupContent { lsp_types::MarkupContent { kind, value } } -fn hover_format(token: &Token, ident: &Ident) -> lsp_types::HoverContents { +fn hover_format( + type_engine: &TypeEngine, + token: &Token, + ident: &Ident, +) -> lsp_types::HoverContents { let token_name: String = ident.as_str().into(); let doc_comment = format_doc_attributes(token); let format_name_with_type = |name: &str, type_id: &TypeId| -> String { - let type_name = format!("{}", type_id); + let type_name = format!("{}", type_engine.help_out(type_id)); format!("{}: {}", name, type_name) }; @@ -106,7 +110,7 @@ fn hover_format(token: &Token, ident: &Ident) -> lsp_types::HoverContents { .and_then(|typed_token| match typed_token { TypedAstToken::TypedDeclaration(decl) => match decl { ty::TyDeclaration::VariableDeclaration(var_decl) => { - let type_name = format!("{}", var_decl.type_ascription); + let type_name = format!("{}", type_engine.help_out(var_decl.type_ascription)); Some(format_variable_hover( var_decl.mutability.is_mutable(), &type_name, @@ -158,7 +162,9 @@ fn hover_format(token: &Token, ident: &Ident) -> lsp_types::HoverContents { Some(format_name_with_type(field.name.as_str(), &field.type_id)) } TypedAstToken::TypedExpression(expr) => match expr.expression { - ty::TyExpressionVariant::Literal { .. } => Some(format!("{}", expr.return_type)), + ty::TyExpressionVariant::Literal { .. } => { + Some(format!("{}", type_engine.help_out(expr.return_type))) + } _ => None, }, _ => None, diff --git a/sway-lsp/src/capabilities/inlay_hints.rs b/sway-lsp/src/capabilities/inlay_hints.rs index d5fc9e1a2c9..aa4d63b6fc4 100644 --- a/sway-lsp/src/capabilities/inlay_hints.rs +++ b/sway-lsp/src/capabilities/inlay_hints.rs @@ -35,6 +35,8 @@ pub(crate) fn inlay_hints( return None; } + let type_engine = session.type_engine.read(); + let hints: Vec = session .tokens_for_file(uri) .filter_map(|(_, token)| { @@ -56,7 +58,7 @@ pub(crate) fn inlay_hints( }) }) .filter_map(|var| { - let type_info = sway_core::type_system::look_up_type_id(var.type_ascription); + let type_info = type_engine.look_up_type_id(var.type_ascription); match type_info { TypeInfo::Unknown | TypeInfo::UnknownGeneric { .. } => None, _ => Some(var), @@ -65,7 +67,7 @@ pub(crate) fn inlay_hints( .map(|var| { let range = crate::utils::common::get_range_from_span(&var.name.span()); let kind = InlayKind::TypeHint; - let label = format!("{}", var.type_ascription); + let label = format!("{}", type_engine.help_out(var.type_ascription)); let inlay_hint = InlayHint { range, kind, label }; self::inlay_hint(config.render_colons, inlay_hint) }) diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index 7538b4cc270..9f1fb79214c 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -23,7 +23,7 @@ use sway_core::{ parsed::{AstNode, ParseProgram}, ty, }, - CompileResult, + CompileResult, TypeEngine, }; use sway_types::{Ident, Span, Spanned}; use sway_utils::helpers::get_sway_files; @@ -48,6 +48,7 @@ pub struct Session { pub runnables: DashMap, pub compiled_program: RwLock, pub sync: SyncWorkspace, + pub type_engine: RwLock, } impl Session { @@ -58,10 +59,13 @@ impl Session { runnables: DashMap::new(), compiled_program: RwLock::new(Default::default()), sync: SyncWorkspace::new(), + type_engine: <_>::default(), } } pub fn init(&self, uri: &Url) -> Result { + *self.type_engine.write() = <_>::default(); + let manifest_dir = PathBuf::from(uri.path()); // Create a new temp dir that clones the current workspace // and store manifest and temp paths @@ -144,7 +148,9 @@ impl Session { /// Return the `Ident` of the declaration of the provided token. pub fn declared_token_ident(&self, token: &Token) -> Option { token.type_def.as_ref().and_then(|type_def| match type_def { - TypeDefinition::TypeId(type_id) => utils::token::ident_of_type_id(type_id), + TypeDefinition::TypeId(type_id) => { + utils::token::ident_of_type_id(&self.type_engine.read(), type_id) + } TypeDefinition::Ident(ident) => Some(ident.clone()), }) } @@ -155,7 +161,7 @@ impl Session { pub fn declared_token_span(&self, token: &Token) -> Option { token.type_def.as_ref().and_then(|type_def| match type_def { TypeDefinition::TypeId(type_id) => { - Some(utils::token::ident_of_type_id(type_id)?.span()) + Some(utils::token::ident_of_type_id(&self.type_engine.read(), type_id)?.span()) } TypeDefinition::Ident(ident) => Some(ident.span()), }) @@ -219,7 +225,9 @@ impl Session { .map_err(LanguageServerError::BuildPlanFailed)?; let mut diagnostics = Vec::new(); - let results = pkg::check(&plan, true).map_err(LanguageServerError::FailedToCompile)?; + let type_engine = &*self.type_engine.read(); + let results = + pkg::check(&plan, true, type_engine).map_err(LanguageServerError::FailedToCompile)?; let results_len = results.len(); for (i, res) in results.into_iter().enumerate() { // We can convert these destructured elements to a Vec later on. @@ -245,11 +253,15 @@ impl Session { // The final element in the results is the main program. if i == results_len - 1 { // First, populate our token_map with un-typed ast nodes. - self.parse_ast_to_tokens(parse_program, traverse_parse_tree::traverse_node); + self.parse_ast_to_tokens(parse_program, |an, tm| { + traverse_parse_tree::traverse_node(type_engine, an, tm) + }); // Next, create runnables and populate our token_map with typed ast nodes. self.create_runnables(typed_program); - self.parse_ast_to_typed_tokens(typed_program, traverse_typed_tree::traverse_node); + self.parse_ast_to_typed_tokens(typed_program, |an, tm| { + traverse_typed_tree::traverse_node(type_engine, an, tm) + }); self.save_parse_program(parse_program.to_owned().clone()); self.save_typed_program(typed_program.to_owned().clone()); diff --git a/sway-lsp/src/core/traverse_parse_tree.rs b/sway-lsp/src/core/traverse_parse_tree.rs index 7ef86f2c563..7d91a50d274 100644 --- a/sway-lsp/src/core/traverse_parse_tree.rs +++ b/sway-lsp/src/core/traverse_parse_tree.rs @@ -19,17 +19,21 @@ use sway_core::{ Literal, }, type_system::{TypeArgument, TypeParameter}, - TypeInfo, + TypeEngine, TypeInfo, }; use sway_types::constants::{DESTRUCTURE_PREFIX, MATCH_RETURN_VAR_NAME_PREFIX, TUPLE_NAME_PREFIX}; use sway_types::{Ident, Span, Spanned}; -pub fn traverse_node(node: &AstNode, tokens: &TokenMap) { +pub fn traverse_node(type_engine: &TypeEngine, node: &AstNode, tokens: &TokenMap) { match &node.content { - AstNodeContent::Declaration(declaration) => handle_declaration(declaration, tokens), - AstNodeContent::Expression(expression) => handle_expression(expression, tokens), + AstNodeContent::Declaration(declaration) => { + handle_declaration(type_engine, declaration, tokens) + } + AstNodeContent::Expression(expression) => { + handle_expression(type_engine, expression, tokens) + } AstNodeContent::ImplicitReturnExpression(expression) => { - handle_expression(expression, tokens) + handle_expression(type_engine, expression, tokens) } // TODO @@ -38,18 +42,22 @@ pub fn traverse_node(node: &AstNode, tokens: &TokenMap) { }; } -fn handle_function_declation(func: &FunctionDeclaration, tokens: &TokenMap) { +fn handle_function_declation( + type_engine: &TypeEngine, + func: &FunctionDeclaration, + tokens: &TokenMap, +) { let token = Token::from_parsed( AstToken::FunctionDeclaration(func.clone()), SymbolKind::Function, ); tokens.insert(to_ident_key(&func.name), token.clone()); for node in &func.body.contents { - traverse_node(node, tokens); + traverse_node(type_engine, node, tokens); } for parameter in &func.parameters { - collect_function_parameter(parameter, tokens); + collect_function_parameter(type_engine, parameter, tokens); } for type_param in &func.type_parameters { @@ -61,6 +69,7 @@ fn handle_function_declation(func: &FunctionDeclaration, tokens: &TokenMap) { } collect_type_info_token( + type_engine, tokens, &token, &func.return_type, @@ -69,7 +78,7 @@ fn handle_function_declation(func: &FunctionDeclaration, tokens: &TokenMap) { ); } -fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { +fn handle_declaration(type_engine: &TypeEngine, declaration: &Declaration, tokens: &TokenMap) { match declaration { Declaration::VariableDeclaration(variable) => { // Don't collect tokens if the ident's name contains __tuple_ || __match_return_var_name_ @@ -98,6 +107,7 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { if let Some(type_ascription_span) = &variable.type_ascription_span { collect_type_info_token( + type_engine, tokens, &token, &variable.type_ascription, @@ -106,10 +116,10 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { ); } } - handle_expression(&variable.body, tokens); + handle_expression(type_engine, &variable.body, tokens); } Declaration::FunctionDeclaration(func) => { - handle_function_declation(func, tokens); + handle_function_declation(type_engine, func, tokens); } Declaration::TraitDeclaration(trait_decl) => { tokens.insert( @@ -121,11 +131,11 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { ); for trait_fn in &trait_decl.interface_surface { - collect_trait_fn(trait_fn, tokens); + collect_trait_fn(type_engine, trait_fn, tokens); } for func_dec in &trait_decl.methods { - handle_function_declation(func_dec, tokens); + handle_function_declation(type_engine, func_dec, tokens); } } Declaration::StructDeclaration(struct_dec) => { @@ -142,6 +152,7 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { tokens.insert(to_ident_key(&field.name), token.clone()); collect_type_info_token( + type_engine, tokens, &token, &field.type_info, @@ -178,6 +189,7 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { tokens.insert(to_ident_key(&variant.name), token.clone()); collect_type_info_token( + type_engine, tokens, &token, &variant.type_info, @@ -209,7 +221,7 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { to_ident_key(&Ident::new(impl_trait.type_implementing_for_span.clone())), Token::from_parsed( AstToken::Declaration(declaration.clone()), - type_info_to_symbol_kind(&impl_trait.type_implementing_for), + type_info_to_symbol_kind(type_engine, &impl_trait.type_implementing_for), ), ); @@ -222,7 +234,7 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { } for func_dec in &impl_trait.functions { - handle_function_declation(func_dec, tokens); + handle_function_declation(type_engine, func_dec, tokens); } } Declaration::ImplSelf(impl_self) => { @@ -237,7 +249,7 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { ); tokens.insert(to_ident_key(name), token.clone()); if let Some(args) = type_arguments { - collect_type_args(args, &token, tokens); + collect_type_args(type_engine, args, &token, tokens); } } @@ -250,7 +262,7 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { } for func_dec in &impl_self.functions { - handle_function_declation(func_dec, tokens); + handle_function_declation(type_engine, func_dec, tokens); } } Declaration::AbiDeclaration(abi_decl) => { @@ -263,7 +275,7 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { ); for trait_fn in &abi_decl.interface_surface { - collect_trait_fn(trait_fn, tokens); + collect_trait_fn(type_engine, trait_fn, tokens); } } Declaration::ConstantDeclaration(const_decl) => { @@ -274,13 +286,14 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { tokens.insert(to_ident_key(&const_decl.name), token.clone()); collect_type_info_token( + type_engine, tokens, &token, &const_decl.type_ascription, const_decl.type_ascription_span.clone(), None, ); - handle_expression(&const_decl.value, tokens); + handle_expression(type_engine, &const_decl.value, tokens); } Declaration::StorageDeclaration(storage_decl) => { for field in &storage_decl.fields { @@ -289,19 +302,20 @@ fn handle_declaration(declaration: &Declaration, tokens: &TokenMap) { tokens.insert(to_ident_key(&field.name), token.clone()); collect_type_info_token( + type_engine, tokens, &token, &field.type_info, Some(field.type_info_span.clone()), None, ); - handle_expression(&field.initializer, tokens); + handle_expression(type_engine, &field.initializer, tokens); } } } } -fn handle_expression(expression: &Expression, tokens: &TokenMap) { +fn handle_expression(type_engine: &TypeEngine, expression: &Expression, tokens: &TokenMap) { let span = &expression.span; match &expression.kind { ExpressionKind::Error(_part_spans) => { @@ -339,16 +353,21 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { tokens.insert(to_ident_key(&call_path_binding.inner.suffix), token.clone()); - collect_type_args(&call_path_binding.type_arguments, &token, tokens); + collect_type_args( + type_engine, + &call_path_binding.type_arguments, + &token, + tokens, + ); } for exp in arguments { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } } ExpressionKind::LazyOperator(LazyOperatorExpression { lhs, rhs, .. }) => { - handle_expression(lhs, tokens); - handle_expression(rhs, tokens); + handle_expression(type_engine, lhs, tokens); + handle_expression(type_engine, rhs, tokens); } ExpressionKind::Variable(name) => { if !name.as_str().contains(TUPLE_NAME_PREFIX) @@ -368,15 +387,15 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { } ExpressionKind::Tuple(fields) => { for exp in fields { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } } ExpressionKind::TupleIndex(TupleIndexExpression { prefix, .. }) => { - handle_expression(prefix, tokens); + handle_expression(type_engine, prefix, tokens); } ExpressionKind::Array(contents) => { for exp in contents { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } } ExpressionKind::Struct(struct_expression) => { @@ -400,7 +419,7 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { let token = Token::from_parsed(AstToken::Expression(expression.clone()), SymbolKind::Struct); tokens.insert(to_ident_key(name), token.clone()); - collect_type_args(type_arguments, &token, tokens); + collect_type_args(type_engine, type_arguments, &token, tokens); for field in fields { tokens.insert( @@ -410,12 +429,12 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { SymbolKind::Field, ), ); - handle_expression(&field.value, tokens); + handle_expression(type_engine, &field.value, tokens); } } ExpressionKind::CodeBlock(contents) => { for node in &contents.contents { - traverse_node(node, tokens); + traverse_node(type_engine, node, tokens); } } ExpressionKind::If(IfExpression { @@ -424,19 +443,19 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { r#else, .. }) => { - handle_expression(condition, tokens); - handle_expression(then, tokens); + handle_expression(type_engine, condition, tokens); + handle_expression(type_engine, then, tokens); if let Some(r#else) = r#else { - handle_expression(r#else, tokens); + handle_expression(type_engine, r#else, tokens); } } ExpressionKind::Match(MatchExpression { value, branches, .. }) => { - handle_expression(value, tokens); + handle_expression(type_engine, value, tokens); for branch in branches { collect_scrutinee(&branch.scrutinee, tokens); - handle_expression(&branch.result, tokens); + handle_expression(type_engine, &branch.result, tokens); } } ExpressionKind::Asm(_) => { @@ -465,7 +484,14 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { SymbolKind::Struct, ); let (type_info, span) = &call_path_binding.inner.suffix; - collect_type_info_token(tokens, &token, type_info, Some(span.clone()), None); + collect_type_info_token( + type_engine, + tokens, + &token, + type_info, + Some(span.clone()), + None, + ); } // Don't collect applications of desugared operators due to mismatched ident lengths. @@ -480,7 +506,7 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { } for exp in arguments { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } for field in contract_call_params { @@ -491,7 +517,7 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { SymbolKind::Field, ), ); - handle_expression(&field.value, tokens); + handle_expression(type_engine, &field.value, tokens); } } ExpressionKind::Subfield(SubfieldExpression { @@ -503,7 +529,7 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { to_ident_key(field_to_access), Token::from_parsed(AstToken::Expression(expression.clone()), SymbolKind::Field), ); - handle_expression(prefix, tokens); + handle_expression(type_engine, prefix, tokens); } ExpressionKind::AmbiguousPathExpression(path_expr) => { let AmbiguousPathExpression { @@ -533,10 +559,15 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { token.clone(), ); - collect_type_args(&call_path_binding.type_arguments, &token, tokens); + collect_type_args( + type_engine, + &call_path_binding.type_arguments, + &token, + tokens, + ); for exp in args { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } } ExpressionKind::DelineatedPath(delineated_path_expression) => { @@ -558,10 +589,15 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { tokens.insert(to_ident_key(&call_path_binding.inner.suffix), token.clone()); - collect_type_args(&call_path_binding.type_arguments, &token, tokens); + collect_type_args( + type_engine, + &call_path_binding.type_arguments, + &token, + tokens, + ); for exp in args { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } } ExpressionKind::AbiCast(abi_cast_expression) => { @@ -579,11 +615,11 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { to_ident_key(&abi_name.suffix), Token::from_parsed(AstToken::Expression(expression.clone()), SymbolKind::Trait), ); - handle_expression(address, tokens); + handle_expression(type_engine, address, tokens); } ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index, .. }) => { - handle_expression(prefix, tokens); - handle_expression(index, tokens); + handle_expression(type_engine, prefix, tokens); + handle_expression(type_engine, index, tokens); } ExpressionKind::StorageAccess(StorageAccessExpression { field_names, .. }) => { for field in field_names { @@ -595,20 +631,20 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { } ExpressionKind::IntrinsicFunction(IntrinsicFunctionExpression { arguments, .. }) => { for argument in arguments { - handle_expression(argument, tokens); + handle_expression(type_engine, argument, tokens); } } ExpressionKind::WhileLoop(WhileLoopExpression { body, condition, .. - }) => handle_while_loop(body, condition, tokens), + }) => handle_while_loop(type_engine, body, condition, tokens), // TODO: collect these tokens as keywords once the compiler returns the span ExpressionKind::Break | ExpressionKind::Continue => {} ExpressionKind::Reassignment(reassignment) => { - handle_expression(&reassignment.rhs, tokens); + handle_expression(type_engine, &reassignment.rhs, tokens); match &reassignment.lhs { ReassignmentTarget::VariableExpression(exp) => { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } ReassignmentTarget::StorageField(idents) => { for ident in idents { @@ -623,14 +659,19 @@ fn handle_expression(expression: &Expression, tokens: &TokenMap) { } } } - ExpressionKind::Return(expr) => handle_expression(expr, tokens), + ExpressionKind::Return(expr) => handle_expression(type_engine, expr, tokens), } } -fn handle_while_loop(body: &CodeBlock, condition: &Expression, tokens: &TokenMap) { - handle_expression(condition, tokens); +fn handle_while_loop( + type_engine: &TypeEngine, + body: &CodeBlock, + condition: &Expression, + tokens: &TokenMap, +) { + handle_expression(type_engine, condition, tokens); for node in &body.contents { - traverse_node(node, tokens); + traverse_node(type_engine, node, tokens); } } @@ -647,15 +688,20 @@ fn literal_to_symbol_kind(value: &Literal) -> SymbolKind { } } -fn collect_type_args(type_arguments: &Vec, token: &Token, tokens: &TokenMap) { +fn collect_type_args( + type_engine: &TypeEngine, + type_arguments: &Vec, + token: &Token, + tokens: &TokenMap, +) { for arg in type_arguments { let mut token = token.clone(); - let type_info = sway_core::type_system::look_up_type_id(arg.type_id); + let type_info = type_engine.look_up_type_id(arg.type_id); // TODO handle tuple and arrays in type_arguments - https://github.com/FuelLabs/sway/issues/2486 if let TypeInfo::Tuple(_) | TypeInfo::Array(_, _, _) = type_info { continue; } - let symbol_kind = type_info_to_symbol_kind(&type_info); + let symbol_kind = type_info_to_symbol_kind(type_engine, &type_info); token.kind = symbol_kind; token.type_def = Some(TypeDefinition::TypeId(arg.type_id)); tokens.insert(to_ident_key(&Ident::new(arg.span.clone())), token); @@ -725,6 +771,7 @@ fn collect_scrutinee(scrutinee: &Scrutinee, tokens: &TokenMap) { } fn collect_type_info_token( + type_engine: &TypeEngine, tokens: &TokenMap, token: &Token, type_info: &TypeInfo, @@ -734,7 +781,7 @@ fn collect_type_info_token( let mut token = token.clone(); match symbol_kind { Some(kind) => token.kind = kind, - None => token.kind = type_info_to_symbol_kind(type_info), + None => token.kind = type_info_to_symbol_kind(type_engine, type_info), } match type_info { @@ -744,7 +791,7 @@ fn collect_type_info_token( } } TypeInfo::Tuple(args) => { - collect_type_args(args, &token, tokens); + collect_type_args(type_engine, args, &token, tokens); } TypeInfo::Custom { name, @@ -753,14 +800,18 @@ fn collect_type_info_token( token.type_def = Some(TypeDefinition::Ident(name.clone())); tokens.insert(to_ident_key(name), token.clone()); if let Some(args) = type_arguments { - collect_type_args(args, &token, tokens); + collect_type_args(type_engine, args, &token, tokens); } } _ => (), } } -fn collect_function_parameter(parameter: &FunctionParameter, tokens: &TokenMap) { +fn collect_function_parameter( + type_engine: &TypeEngine, + parameter: &FunctionParameter, + tokens: &TokenMap, +) { let token = Token::from_parsed( AstToken::FunctionParameter(parameter.clone()), SymbolKind::ValueParam, @@ -768,6 +819,7 @@ fn collect_function_parameter(parameter: &FunctionParameter, tokens: &TokenMap) tokens.insert(to_ident_key(¶meter.name), token.clone()); collect_type_info_token( + type_engine, tokens, &token, ¶meter.type_info, @@ -776,15 +828,16 @@ fn collect_function_parameter(parameter: &FunctionParameter, tokens: &TokenMap) ); } -fn collect_trait_fn(trait_fn: &TraitFn, tokens: &TokenMap) { +fn collect_trait_fn(type_engine: &TypeEngine, trait_fn: &TraitFn, tokens: &TokenMap) { let token = Token::from_parsed(AstToken::TraitFn(trait_fn.clone()), SymbolKind::Function); tokens.insert(to_ident_key(&trait_fn.name), token.clone()); for parameter in &trait_fn.parameters { - collect_function_parameter(parameter, tokens); + collect_function_parameter(type_engine, parameter, tokens); } collect_type_info_token( + type_engine, tokens, &token, &trait_fn.return_type, diff --git a/sway-lsp/src/core/traverse_typed_tree.rs b/sway-lsp/src/core/traverse_typed_tree.rs index 34c42c9bb28..b0842ea36a5 100644 --- a/sway-lsp/src/core/traverse_typed_tree.rs +++ b/sway-lsp/src/core/traverse_typed_tree.rs @@ -7,21 +7,30 @@ use crate::{ use sway_core::{ declaration_engine::{self, de_get_function}, language::ty, + TypeEngine, }; use sway_types::{ident::Ident, Spanned}; -pub fn traverse_node(node: &ty::TyAstNode, tokens: &TokenMap) { +pub fn traverse_node(type_engine: &TypeEngine, node: &ty::TyAstNode, tokens: &TokenMap) { match &node.content { - ty::TyAstNodeContent::Declaration(declaration) => handle_declaration(declaration, tokens), - ty::TyAstNodeContent::Expression(expression) => handle_expression(expression, tokens), + ty::TyAstNodeContent::Declaration(declaration) => { + handle_declaration(type_engine, declaration, tokens) + } + ty::TyAstNodeContent::Expression(expression) => { + handle_expression(type_engine, expression, tokens) + } ty::TyAstNodeContent::ImplicitReturnExpression(expression) => { - handle_expression(expression, tokens) + handle_expression(type_engine, expression, tokens) } ty::TyAstNodeContent::SideEffect => (), }; } -fn handle_declaration(declaration: &ty::TyDeclaration, tokens: &TokenMap) { +fn handle_declaration( + type_engine: &TypeEngine, + declaration: &ty::TyDeclaration, + tokens: &TokenMap, +) { match declaration { ty::TyDeclaration::VariableDeclaration(variable) => { if let Some(mut token) = tokens.get_mut(&to_ident_key(&variable.name)) { @@ -37,7 +46,7 @@ fn handle_declaration(declaration: &ty::TyDeclaration, tokens: &TokenMap) { } } - handle_expression(&variable.body, tokens); + handle_expression(type_engine, &variable.body, tokens); } ty::TyDeclaration::ConstantDeclaration(decl_id) => { if let Ok(const_decl) = @@ -47,14 +56,14 @@ fn handle_declaration(declaration: &ty::TyDeclaration, tokens: &TokenMap) { token.typed = Some(TypedAstToken::TypedDeclaration(declaration.clone())); token.type_def = Some(TypeDefinition::Ident(const_decl.name.clone())); } - handle_expression(&const_decl.value, tokens); + handle_expression(type_engine, &const_decl.value, tokens); } } ty::TyDeclaration::FunctionDeclaration(decl_id) => { if let Ok(func_decl) = declaration_engine::de_get_function(decl_id.clone(), &decl_id.span()) { - collect_typed_fn_decl(&func_decl, tokens); + collect_typed_fn_decl(type_engine, &func_decl, tokens); } } ty::TyDeclaration::TraitDeclaration(decl_id) => { @@ -168,7 +177,7 @@ fn handle_declaration(declaration: &ty::TyDeclaration, tokens: &TokenMap) { if let Ok(method) = declaration_engine::de_get_function(method_id.clone(), &decl_id.span()) { - collect_typed_fn_decl(&method, tokens); + collect_typed_fn_decl(type_engine, &method, tokens); } } } @@ -213,14 +222,14 @@ fn handle_declaration(declaration: &ty::TyDeclaration, tokens: &TokenMap) { token.type_def = Some(TypeDefinition::TypeId(field.type_id)); } - handle_expression(&field.initializer, tokens); + handle_expression(type_engine, &field.initializer, tokens); } } } } } -fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { +fn handle_expression(type_engine: &TypeEngine, expression: &ty::TyExpression, tokens: &TokenMap) { match &expression.expression { ty::TyExpressionVariant::Literal { .. } => { if let Some(mut token) = @@ -253,26 +262,26 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { } for exp in contract_call_params.values() { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } for (ident, exp) in arguments { if let Some(mut token) = tokens.get_mut(&to_ident_key(ident)) { token.typed = Some(TypedAstToken::TypedExpression(exp.clone())); } - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } if let Ok(function_decl) = de_get_function(function_decl_id.clone(), &call_path.span()) { for node in &function_decl.body.contents { - traverse_node(node, tokens); + traverse_node(type_engine, node, tokens); } } } ty::TyExpressionVariant::LazyOperator { lhs, rhs, .. } => { - handle_expression(lhs, tokens); - handle_expression(rhs, tokens); + handle_expression(type_engine, lhs, tokens); + handle_expression(type_engine, rhs, tokens); } ty::TyExpressionVariant::VariableExpression { ref name, ref span, .. @@ -284,17 +293,17 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { } ty::TyExpressionVariant::Tuple { fields } => { for exp in fields { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } } ty::TyExpressionVariant::Array { contents } => { for exp in contents { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } } ty::TyExpressionVariant::ArrayIndex { prefix, index } => { - handle_expression(prefix, tokens); - handle_expression(index, tokens); + handle_expression(type_engine, prefix, tokens); + handle_expression(type_engine, index, tokens); } ty::TyExpressionVariant::StructExpression { fields, span, .. } => { if let Some(mut token) = tokens.get_mut(&to_ident_key(&Ident::new(span.clone()))) { @@ -307,7 +316,7 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { token.typed = Some(TypedAstToken::TypedExpression(field.value.clone())); if let Some(struct_decl) = - &struct_declaration_of_type_id(&expression.return_type, tokens) + &struct_declaration_of_type_id(type_engine, &expression.return_type, tokens) { for decl_field in &struct_decl.fields { if decl_field.name == field.name { @@ -317,12 +326,12 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { } } } - handle_expression(&field.value, tokens); + handle_expression(type_engine, &field.value, tokens); } } ty::TyExpressionVariant::CodeBlock(code_block) => { for node in &code_block.contents { - traverse_node(node, tokens); + traverse_node(type_engine, node, tokens); } } ty::TyExpressionVariant::FunctionParameter { .. } => {} @@ -331,10 +340,10 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { then, r#else, } => { - handle_expression(condition, tokens); - handle_expression(then, tokens); + handle_expression(type_engine, condition, tokens); + handle_expression(type_engine, then, tokens); if let Some(r#else) = r#else { - handle_expression(r#else, tokens); + handle_expression(type_engine, r#else, tokens); } } ty::TyExpressionVariant::AsmExpression { .. } => {} @@ -344,7 +353,7 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { field_instantiation_span, .. } => { - handle_expression(prefix, tokens); + handle_expression(type_engine, prefix, tokens); if let Some(mut token) = tokens.get_mut(&to_ident_key(&Ident::new(field_instantiation_span.clone()))) @@ -354,7 +363,7 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { } } ty::TyExpressionVariant::TupleElemAccess { prefix, .. } => { - handle_expression(prefix, tokens); + handle_expression(type_engine, prefix, tokens); } ty::TyExpressionVariant::EnumInstantiation { variant_name, @@ -379,7 +388,7 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { } if let Some(contents) = contents.as_deref() { - handle_expression(contents, tokens); + handle_expression(type_engine, contents, tokens); } } ty::TyExpressionVariant::AbiCast { @@ -395,7 +404,7 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { token.typed = Some(TypedAstToken::TypedExpression(expression.clone())); } - handle_expression(address, tokens); + handle_expression(type_engine, address, tokens); } ty::TyExpressionVariant::StorageAccess(storage_access) => { for field in &storage_access.fields { @@ -405,25 +414,25 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { } } ty::TyExpressionVariant::IntrinsicFunction(kind) => { - handle_intrinsic_function(kind, tokens); + handle_intrinsic_function(type_engine, kind, tokens); } ty::TyExpressionVariant::AbiName { .. } => {} ty::TyExpressionVariant::EnumTag { exp } => { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); } ty::TyExpressionVariant::UnsafeDowncast { exp, variant } => { - handle_expression(exp, tokens); + handle_expression(type_engine, exp, tokens); if let Some(mut token) = tokens.get_mut(&to_ident_key(&variant.name)) { token.typed = Some(TypedAstToken::TypedExpression(expression.clone())); } } ty::TyExpressionVariant::WhileLoop { body, condition, .. - } => handle_while_loop(body, condition, tokens), + } => handle_while_loop(type_engine, body, condition, tokens), ty::TyExpressionVariant::Break => (), ty::TyExpressionVariant::Continue => (), ty::TyExpressionVariant::Reassignment(reassignment) => { - handle_expression(&reassignment.rhs, tokens); + handle_expression(type_engine, &reassignment.rhs, tokens); if let Some(mut token) = tokens.get_mut(&to_ident_key(&reassignment.lhs_base_name)) { token.typed = Some(TypedAstToken::TypedReassignment((**reassignment).clone())); @@ -434,9 +443,11 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { if let Some(mut token) = tokens.get_mut(&to_ident_key(name)) { token.typed = Some(TypedAstToken::TypedReassignment((**reassignment).clone())); - if let Some(struct_decl) = - &struct_declaration_of_type_id(&reassignment.lhs_type, tokens) - { + if let Some(struct_decl) = &struct_declaration_of_type_id( + type_engine, + &reassignment.lhs_type, + tokens, + ) { for decl_field in &struct_decl.fields { if &decl_field.name == name { token.type_def = @@ -456,25 +467,31 @@ fn handle_expression(expression: &ty::TyExpression, tokens: &TokenMap) { )); } } - handle_expression(&storage_reassignment.rhs, tokens); + handle_expression(type_engine, &storage_reassignment.rhs, tokens); } - ty::TyExpressionVariant::Return(exp) => handle_expression(exp, tokens), + ty::TyExpressionVariant::Return(exp) => handle_expression(type_engine, exp, tokens), } } fn handle_intrinsic_function( + type_engine: &TypeEngine, ty::TyIntrinsicFunctionKind { arguments, .. }: &ty::TyIntrinsicFunctionKind, tokens: &TokenMap, ) { for arg in arguments { - handle_expression(arg, tokens); + handle_expression(type_engine, arg, tokens); } } -fn handle_while_loop(body: &ty::TyCodeBlock, condition: &ty::TyExpression, tokens: &TokenMap) { - handle_expression(condition, tokens); +fn handle_while_loop( + type_engine: &TypeEngine, + body: &ty::TyCodeBlock, + condition: &ty::TyExpression, + tokens: &TokenMap, +) { + handle_expression(type_engine, condition, tokens); for node in &body.contents { - traverse_node(node, tokens); + traverse_node(type_engine, node, tokens); } } @@ -508,14 +525,18 @@ fn collect_typed_fn_param_token(param: &ty::TyFunctionParameter, tokens: &TokenM } } -fn collect_typed_fn_decl(func_decl: &ty::TyFunctionDeclaration, tokens: &TokenMap) { +fn collect_typed_fn_decl( + type_engine: &TypeEngine, + func_decl: &ty::TyFunctionDeclaration, + tokens: &TokenMap, +) { if let Some(mut token) = tokens.get_mut(&to_ident_key(&func_decl.name)) { token.typed = Some(TypedAstToken::TypedFunctionDeclaration(func_decl.clone())); token.type_def = Some(TypeDefinition::Ident(func_decl.name.clone())); } for node in &func_decl.body.contents { - traverse_node(node, tokens); + traverse_node(type_engine, node, tokens); } for parameter in &func_decl.parameters { collect_typed_fn_param_token(parameter, tokens); diff --git a/sway-lsp/src/server.rs b/sway-lsp/src/server.rs index dbc278a3255..68ce1797d49 100644 --- a/sway-lsp/src/server.rs +++ b/sway-lsp/src/server.rs @@ -956,7 +956,7 @@ mod tests { let uri = init_and_open(&mut service, doc_comments_dir()).await; let _ = go_to_definition_request(&mut service, &uri, 44, 19, 1).await; let _ = did_change_request(&mut service, &uri).await; - let _ = go_to_definition_request(&mut service, &uri, 45, 20, 2).await; + let _ = go_to_definition_request(&mut service, &uri, 45, 19, 2).await; shutdown_and_exit(&mut service).await; } diff --git a/sway-lsp/src/utils/token.rs b/sway-lsp/src/utils/token.rs index b587d4c3c44..3c7afde4054 100644 --- a/sway-lsp/src/utils/token.rs +++ b/sway-lsp/src/utils/token.rs @@ -3,6 +3,7 @@ use sway_core::{ declaration_engine, language::ty, type_system::{TypeId, TypeInfo}, + TypeEngine, }; use sway_types::{ident::Ident, span::Span, Spanned}; @@ -42,10 +43,11 @@ pub(crate) fn to_ident_key(ident: &Ident) -> (Ident, Span) { /// Uses the TypeId to find the associated TypedDeclaration in the TokenMap. pub(crate) fn declaration_of_type_id( + type_engine: &TypeEngine, type_id: &TypeId, tokens: &TokenMap, ) -> Option { - ident_of_type_id(type_id) + ident_of_type_id(type_engine, type_id) .and_then(|decl_ident| tokens.try_get(&to_ident_key(&decl_ident)).try_unwrap()) .map(|item| item.value().clone()) .and_then(|token| token.typed) @@ -58,10 +60,11 @@ pub(crate) fn declaration_of_type_id( /// Returns the TypedStructDeclaration associated with the TypeId if it /// exists within the TokenMap. pub(crate) fn struct_declaration_of_type_id( + type_engine: &TypeEngine, type_id: &TypeId, tokens: &TokenMap, ) -> Option { - declaration_of_type_id(type_id, tokens).and_then(|decl| match decl { + declaration_of_type_id(type_engine, type_id, tokens).and_then(|decl| match decl { ty::TyDeclaration::StructDeclaration(ref decl_id) => { declaration_engine::de_get_struct(decl_id.clone(), &decl_id.span()).ok() } @@ -70,9 +73,8 @@ pub(crate) fn struct_declaration_of_type_id( } /// Use the TypeId to look up the associated TypeInfo and return the Ident if one is found. -pub(crate) fn ident_of_type_id(type_id: &TypeId) -> Option { - let type_info = sway_core::type_system::look_up_type_id(*type_id); - match type_info { +pub(crate) fn ident_of_type_id(type_engine: &TypeEngine, type_id: &TypeId) -> Option { + match type_engine.look_up_type_id(*type_id) { TypeInfo::UnknownGeneric { name, .. } | TypeInfo::Enum { name, .. } | TypeInfo::Struct { name, .. } @@ -81,7 +83,10 @@ pub(crate) fn ident_of_type_id(type_id: &TypeId) -> Option { } } -pub(crate) fn type_info_to_symbol_kind(type_info: &TypeInfo) -> SymbolKind { +pub(crate) fn type_info_to_symbol_kind( + type_engine: &TypeEngine, + type_info: &TypeInfo, +) -> SymbolKind { match type_info { TypeInfo::UnsignedInteger(..) | TypeInfo::Boolean | TypeInfo::Str(..) | TypeInfo::B256 => { SymbolKind::BuiltinType @@ -90,8 +95,8 @@ pub(crate) fn type_info_to_symbol_kind(type_info: &TypeInfo) -> SymbolKind { TypeInfo::Custom { .. } | TypeInfo::Struct { .. } => SymbolKind::Struct, TypeInfo::Enum { .. } => SymbolKind::Enum, TypeInfo::Array(type_id, ..) => { - let type_info = sway_core::type_system::look_up_type_id(*type_id); - type_info_to_symbol_kind(&type_info) + let type_info = type_engine.look_up_type_id(*type_id); + type_info_to_symbol_kind(type_engine, &type_info) } _ => SymbolKind::Unknown, } diff --git a/sway-parse/src/lib.rs b/sway-parse/src/lib.rs index 71916281883..d0f77e81a94 100644 --- a/sway-parse/src/lib.rs +++ b/sway-parse/src/lib.rs @@ -24,7 +24,7 @@ pub use crate::{ token::{lex, lex_commented}, }; -use sway_ast::Module; +use sway_ast::{Module, ModuleKind}; use sway_error::handler::{ErrorEmitted, Handler}; use std::{path::PathBuf, sync::Arc}; @@ -37,3 +37,12 @@ pub fn parse_file( let ts = lex(handler, &src, 0, src.len(), path)?; Parser::new(handler, &ts).parse_to_end().map(|(m, _)| m) } + +pub fn parse_module_kind( + handler: &Handler, + src: Arc, + path: Option>, +) -> Result { + let ts = lex(handler, &src, 0, src.len(), path)?; + Parser::new(handler, &ts).parse() +} diff --git a/test/src/ir_generation/mod.rs b/test/src/ir_generation/mod.rs index 0875f6446e3..8e1c36386ac 100644 --- a/test/src/ir_generation/mod.rs +++ b/test/src/ir_generation/mod.rs @@ -8,12 +8,13 @@ use anyhow::Result; use colored::Colorize; use sway_core::{ compile_ir_to_asm, compile_to_ast, inline_function_calls, ir_generation::compile_program, - namespace, + namespace, TypeEngine, }; pub(super) async fn run(filter_regex: Option<®ex::Regex>) -> Result<()> { // Compile core library and reuse it when compiling tests. - let core_lib = compile_core(); + let type_engine = TypeEngine::default(); + let core_lib = compile_core(&type_engine); // Find all the tests. let all_tests = discover_test_files(); @@ -114,8 +115,12 @@ pub(super) async fn run(filter_regex: Option<®ex::Regex>) -> Result<()> { PathBuf::from("/"), ); let sway_str = String::from_utf8_lossy(&sway_str); - let typed_res = - compile_to_ast(Arc::from(sway_str), core_lib.clone(), Some(&bld_cfg)); + let typed_res = compile_to_ast( + &type_engine, + Arc::from(sway_str), + core_lib.clone(), + Some(&bld_cfg), + ); if !typed_res.errors.is_empty() { panic!( "Failed to compile test {}:\n{}", @@ -137,7 +142,7 @@ pub(super) async fn run(filter_regex: Option<®ex::Regex>) -> Result<()> { // Compile to IR. let include_tests = false; - let mut ir = compile_program(typed_program, include_tests) + let mut ir = compile_program(typed_program, include_tests, &type_engine) .unwrap_or_else(|e| { panic!("Failed to compile test {}:\n{e}", path.display()); }) @@ -283,7 +288,7 @@ fn discover_test_files() -> Vec { test_files } -fn compile_core() -> namespace::Module { +fn compile_core(type_engine: &TypeEngine) -> namespace::Module { let manifest_dir = env!("CARGO_MANIFEST_DIR"); let libcore_root_dir = format!("{manifest_dir}/../sway-lib-core"); @@ -294,7 +299,7 @@ fn compile_core() -> namespace::Module { locked: false, }; - let res = forc::test::forc_check::check(check_cmd) + let res = forc::test::forc_check::check(check_cmd, type_engine) .expect("Failed to compile sway-lib-core for IR tests."); match res.value {