diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 50d8b24c703..69393afd652 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -40,7 +40,7 @@ use sway_core::{ fuel_crypto, fuel_tx::{self, Contract, ContractId, StorageSlot}, }, - language::{parsed::TreeType, Visibility}, + language::parsed::TreeType, semantic_analysis::namespace, source_map::SourceMap, transform::AttributeKind, @@ -49,7 +49,7 @@ use sway_core::{ use sway_core::{set_bytecode_configurables_offset, PrintAsm, PrintIr}; use sway_error::{error::CompileError, handler::Handler, warning::CompileWarning}; use sway_features::ExperimentalFeatures; -use sway_types::constants::{CORE, PRELUDE, STD}; +use sway_types::constants::{CORE, STD}; use sway_types::{Ident, Span, Spanned}; use sway_utils::{constants, time_expr, PerformanceData, PerformanceMetric}; use tracing::{debug, info}; @@ -181,7 +181,7 @@ pub struct CompiledPackage { pub program_abi: ProgramABI, pub storage_slots: Vec, pub bytecode: BuiltPackageBytecode, - pub root_module: namespace::Module, + pub root_module: namespace::Root, pub warnings: Vec, pub metrics: PerformanceData, } @@ -1566,9 +1566,6 @@ pub fn sway_build_config( Ok(build_config) } -/// The name of the constant holding the contract's id. -pub const CONTRACT_ID_CONSTANT_NAME: &str = "CONTRACT_ID"; - /// Builds the dependency namespace for the package at the given node index within the graph. /// /// This function is designed to be called for each node in order of compilation. @@ -1582,7 +1579,7 @@ pub const CONTRACT_ID_CONSTANT_NAME: &str = "CONTRACT_ID"; /// `contract_id_value` should only be Some when producing the `dependency_namespace` for a contract with tests enabled. /// This allows us to provide a contract's `CONTRACT_ID` constant to its own unit tests. pub fn dependency_namespace( - lib_namespace_map: &HashMap, + lib_namespace_map: &HashMap, compiled_contract_deps: &CompiledContractDeps, graph: &Graph, node: NodeIx, @@ -1593,30 +1590,25 @@ pub fn dependency_namespace( // TODO: Clean this up when config-time constants v1 are removed. let node_idx = &graph[node]; let name = Ident::new_no_span(node_idx.name.clone()); - let mut root_module = if let Some(contract_id_value) = contract_id_value { - namespace::default_with_contract_id( - engines, - name.clone(), - Visibility::Public, - contract_id_value, - experimental, - )? - } else { - namespace::Module::new(name, Visibility::Public, None) - }; - + let mut root_namespace = + if let Some(contract_id_value) = contract_id_value { + namespace::namespace_with_contract_id(engines, name.clone(), contract_id_value, experimental)? + } else { + namespace::namespace_without_contract_id(name.clone()) + }; + // Add direct dependencies. let mut core_added = false; for edge in graph.edges_directed(node, Direction::Outgoing) { let dep_node = edge.target(); let dep_name = kebab_to_snake_case(&edge.weight().name); let dep_edge = edge.weight(); - let mut dep_namespace = match dep_edge.kind { + let dep_namespace = match dep_edge.kind { DepKind::Library => lib_namespace_map .get(&dep_node) .cloned() - .expect("no namespace module") - .read(engines, Clone::clone), + .expect("no root module") + .clone(), DepKind::Contract { salt } => { let dep_contract_id = compiled_contract_deps .get(&dep_node) @@ -1627,17 +1619,10 @@ pub fn dependency_namespace( let contract_id_value = format!("0x{dep_contract_id}"); let node_idx = &graph[dep_node]; let name = Ident::new_no_span(node_idx.name.clone()); - namespace::default_with_contract_id( - engines, - name.clone(), - Visibility::Private, - contract_id_value, - experimental, - )? + namespace::namespace_with_contract_id(engines, name.clone(), contract_id_value, experimental)? } }; - dep_namespace.is_external = true; - root_module.insert_submodule(dep_name, dep_namespace); + root_namespace.add_external(dep_name, dep_namespace); let dep = &graph[dep_node]; if dep.name == CORE { core_added = true; @@ -1648,51 +1633,29 @@ pub fn dependency_namespace( if !core_added { if let Some(core_node) = find_core_dep(graph, node) { let core_namespace = &lib_namespace_map[&core_node]; - root_module.insert_submodule(CORE.to_string(), core_namespace.clone()); - core_added = true; + root_namespace.add_external(CORE.to_string(), core_namespace.clone()); +// core_added = true; } } - let mut root = namespace::Root::from(root_module); - - if core_added { - let _ = root.star_import( - &Handler::default(), - engines, - &[CORE, PRELUDE].map(|s| Ident::new_no_span(s.into())), - &[], - Visibility::Private, - ); - } - - if has_std_dep(graph, node) { - let _ = root.star_import( - &Handler::default(), - engines, - &[STD, PRELUDE].map(|s| Ident::new_no_span(s.into())), - &[], - Visibility::Private, - ); - } - - Ok(root) + Ok(root_namespace) } -/// Find the `std` dependency, if it is a direct one, of the given node. -fn has_std_dep(graph: &Graph, node: NodeIx) -> bool { - // If we are `std`, do nothing. - let pkg = &graph[node]; - if pkg.name == STD { - return false; - } - - // If we have `std` as a direct dep, use it. - graph.edges_directed(node, Direction::Outgoing).any(|edge| { - let dep_node = edge.target(); - let dep = &graph[dep_node]; - matches!(&dep.name[..], STD) - }) -} +///// Find the `std` dependency, if it is a direct one, of the given node. +//fn has_std_dep(graph: &Graph, node: NodeIx) -> bool { +// // If we are `std`, do nothing. +// let pkg = &graph[node]; +// if pkg.name == STD { +// return false; +// } +// +// // If we have `std` as a direct dep, use it. +// graph.edges_directed(node, Direction::Outgoing).any(|edge| { +// let dep_node = edge.target(); +// let dep = &graph[dep_node]; +// matches!(&dep.name[..], STD) +// }) +//} /// Find the `core` dependency (whether direct or transitive) for the given node if it exists. fn find_core_dep(graph: &Graph, node: NodeIx) -> Option { @@ -1752,7 +1715,7 @@ pub fn compile( pkg: &PackageDescriptor, profile: &BuildProfile, engines: &Engines, - namespace: &mut namespace::Root, + namespace: namespace::Root, source_map: &mut SourceMap, experimental: ExperimentalFeatures, ) -> Result { @@ -1966,7 +1929,7 @@ pub fn compile( storage_slots, tree_type, bytecode, - root_module: namespace.root_module().clone(), + root_module: namespace.root().clone(), warnings, metrics, }; @@ -2398,7 +2361,7 @@ pub fn build( // `ContractIdConst` is a None here since we do not yet have a // contract ID value at this point. - let mut dep_namespace = match dependency_namespace( + let dep_namespace = match dependency_namespace( &lib_namespace_map, &compiled_contract_deps, plan.graph(), @@ -2415,7 +2378,7 @@ pub fn build( &descriptor, &profile, &engines, - &mut dep_namespace, + dep_namespace, &mut source_map, experimental, )?; @@ -2463,7 +2426,7 @@ pub fn build( }; // Note that the contract ID value here is only Some if tests are enabled. - let mut dep_namespace = match dependency_namespace( + let dep_namespace = match dependency_namespace( &lib_namespace_map, &compiled_contract_deps, plan.graph(), @@ -2489,7 +2452,7 @@ pub fn build( &descriptor, &profile, &engines, - &mut dep_namespace, + dep_namespace, &mut source_map, experimental, )?; @@ -2569,7 +2532,7 @@ pub fn check( let contract_id_value = (idx == plan.compilation_order.len() - 1).then(|| DUMMY_CONTRACT_ID.to_string()); - let mut dep_namespace = dependency_namespace( + let dep_namespace = dependency_namespace( &lib_namespace_map, &compiled_contract_deps, &plan.graph, @@ -2600,7 +2563,7 @@ pub fn check( &handler, engines, input, - &mut dep_namespace, + dep_namespace, Some(&build_config), &pkg.name, retrigger_compilation.clone(), @@ -2624,12 +2587,12 @@ pub fn check( if let Ok(typed_program) = programs.typed.as_ref() { if let TreeType::Library = typed_program.kind.tree_type() { - let mut module = typed_program + let mut lib_root = typed_program .root .namespace - .program_id(engines) - .read(engines, |m| m.clone()); - module.set_span( + .clone() + .root(); + lib_root.add_span_to_root_module( Span::new( manifest.entry_string()?, 0, @@ -2638,7 +2601,7 @@ pub fn check( ) .unwrap(), ); - lib_namespace_map.insert(node, module); + lib_namespace_map.insert(node, lib_root); } source_map.insert_dependency(manifest.dir()); } else { diff --git a/sway-core/src/abi_generation/fuel_abi.rs b/sway-core/src/abi_generation/fuel_abi.rs index 7fdd704155d..94bff84ddfd 100644 --- a/sway-core/src/abi_generation/fuel_abi.rs +++ b/sway-core/src/abi_generation/fuel_abi.rs @@ -21,14 +21,16 @@ pub struct AbiContext<'a> { } impl<'a> AbiContext<'a> { - fn to_str_context(&self, engines: &Engines, abi_full: bool) -> AbiStrContext { + fn to_str_context( + &self, + abi_full: bool, + ) -> AbiStrContext { AbiStrContext { program_name: self .program .root .namespace - .program_id(engines) - .read(engines, |m| m.name().to_string()), + .current_package_name().to_string(), abi_with_callpaths: self.abi_with_callpaths, abi_with_fully_specified_types: abi_full, abi_root_type_without_generic_type_parameters: !abi_full, @@ -50,8 +52,8 @@ impl TypeId { .program .root .namespace - .program_id(engines) - .read(engines, |m| m.name().clone().as_str().to_string()), + .current_package_name() + .to_string(), abi_with_callpaths: true, abi_with_fully_specified_types: true, abi_root_type_without_generic_type_parameters: false, @@ -382,7 +384,7 @@ fn generate_concrete_type_declaration( let type_metadata_decl = program_abi::TypeMetadataDeclaration { metadata_type_id: MetadataTypeId(type_id.index()), type_field: type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), + &ctx.to_str_context(false), engines, resolved_type_id, ), @@ -476,7 +478,7 @@ fn generate_type_metadata_declaration( let type_metadata_decl = program_abi::TypeMetadataDeclaration { metadata_type_id: MetadataTypeId(type_id.index()), type_field: type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), + &ctx.to_str_context(false), engines, resolved_type_id, ), @@ -1249,7 +1251,7 @@ impl TypeParameter { let type_parameter = program_abi::TypeMetadataDeclaration { metadata_type_id: type_id.clone(), type_field: self.initial_type_id.get_abi_type_str( - &ctx.to_str_context(engines, false), + &ctx.to_str_context(false), engines, self.type_id, ), 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 60843dbf3dd..b009fa482e4 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -7,7 +7,7 @@ use crate::{ self, ConfigurableDecl, ConstantDecl, FunctionDecl, ProjectionKind, StructDecl, TraitDecl, TyAstNode, TyAstNodeContent, TyDecl, TyImplItem, TypeAliasDecl, }, - CallPath, Visibility, + CallPath, CallPathType, Visibility, }, transform::{self, AttributesMap}, type_system::TypeInfo, @@ -857,7 +857,7 @@ fn connect_trait_declaration( CallPath { prefixes: vec![], suffix: decl.name.clone(), - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, TraitNamespaceEntry { trait_idx: entry_node, @@ -881,7 +881,7 @@ fn connect_abi_declaration( CallPath { prefixes: vec![], suffix: decl.name.clone(), - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, TraitNamespaceEntry { trait_idx: entry_node, diff --git a/sway-core/src/ir_generation.rs b/sway-core/src/ir_generation.rs index 10df2f19a9b..a1be209352a 100644 --- a/sway-core/src/ir_generation.rs +++ b/sway-core/src/ir_generation.rs @@ -166,7 +166,7 @@ pub fn compile_program<'eng>( engines, &mut ctx, entry_function, - root.namespace.module(engines), + root.namespace.current_module(), &logged_types, &messages_types, &test_fns, @@ -176,7 +176,7 @@ pub fn compile_program<'eng>( engines, &mut ctx, entry_function, - root.namespace.module(engines), + root.namespace.current_module(), &logged_types, &messages_types, &test_fns, @@ -189,7 +189,7 @@ pub fn compile_program<'eng>( &mut ctx, entry_function.as_ref(), abi_entries, - root.namespace.module(engines), + root.namespace.current_module(), declarations, &logged_types, &messages_types, @@ -200,7 +200,7 @@ pub fn compile_program<'eng>( ty::TyProgramKind::Library { .. } => compile::compile_library( engines, &mut ctx, - root.namespace.module(engines), + root.namespace.current_module(), &logged_types, &messages_types, &test_fns, diff --git a/sway-core/src/language/call_path.rs b/sway-core/src/language/call_path.rs index 8036d3ecab8..0f8580b2442 100644 --- a/sway-core/src/language/call_path.rs +++ b/sway-core/src/language/call_path.rs @@ -88,7 +88,7 @@ impl std::convert::From for QualifiedCallPath { call_path: CallPath { prefixes: vec![], suffix: other, - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, qualified_path_root: None, } @@ -177,15 +177,34 @@ impl DebugWithEngines for QualifiedCallPath { } } +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub enum CallPathType { + /// An unresolved path on the form `::X::Y::Z`. The path must be resolved relative to the package + /// root module. + /// The path can be converted to a full path by prepending the package name, so if the path + /// `::X::Y::Z` occurs in package `A`, then the corresponding full path will be `A::X::Y::Z`. + RelativeToPackageRoot, + /// An unresolved path on the form `X::Y::Z`. The path must either be resolved relative to the + /// current module, in which case `X` is either a submodule or a name bound in the current + /// module, or as a full path, in which case `X` is the name of the current package. + /// If the path is resolved relative to the current module, and the current module has a module + /// path `A::B::C`, then the corresponding full path is `A::B::C::X::Y::Z`. + /// If the path is resolved as a full path, then the full path is obviously `X::Y::Z`. + Ambiguous, + /// A full path on the form `X::Y::Z`. The first identifier `X` refers to the current package + /// name. After that comes a (possibly empty) series of names of submodules. Then comes the name + /// of an item (a type, a trait, a function, or something else declared in that + /// module). Additionally, there may be additional names such as the name of an enum variant. + Full, +} + /// In the expression `a::b::c()`, `a` and `b` are the prefixes and `c` is the suffix. /// `c` can be any type `T`, but in practice `c` is either an `Ident` or a `TypeInfo`. #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct CallPath { pub prefixes: Vec, pub suffix: T, - // If `is_absolute` is true, then this call path is an absolute path from - // the project root namespace. If not, then it is relative to the current namespace. - pub is_absolute: bool, + pub callpath_type: CallPathType, } impl EqWithEngines for CallPath {} @@ -193,8 +212,9 @@ impl PartialEqWithEngines for CallPath { fn eq(&self, other: &Self, _ctx: &PartialEqWithEnginesContext) -> bool { self.prefixes == other.prefixes && self.suffix == other.suffix - && self.is_absolute == other.is_absolute + && self.callpath_type == other.callpath_type } + } impl EqWithEngines for CallPath {} @@ -202,7 +222,7 @@ impl PartialEqWithEngines for CallPath { fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { self.prefixes == other.prefixes && self.suffix.eq(&other.suffix, ctx) - && self.is_absolute == other.is_absolute + && self.callpath_type == other.callpath_type } } @@ -211,7 +231,7 @@ impl OrdWithEngines for CallPath { self.prefixes .cmp(&other.prefixes) .then_with(|| self.suffix.cmp(&other.suffix, ctx)) - .then_with(|| self.is_absolute.cmp(&other.is_absolute)) + .then_with(|| self.callpath_type.cmp(&other.callpath_type)) } } @@ -226,7 +246,7 @@ impl std::convert::From for CallPath { CallPath { prefixes: vec![], suffix: other, - is_absolute: false, + callpath_type: CallPathType::Ambiguous, } } } @@ -286,7 +306,7 @@ impl Spanned for CallPath { } impl CallPath { - pub fn absolute(path: &[&str]) -> Self { + pub fn fullpath(path: &[&str]) -> Self { assert!(!path.is_empty()); CallPath { @@ -296,7 +316,7 @@ impl CallPath { .map(|&x| Ident::new_no_span(x.into())) .collect(), suffix: path.last().map(|&x| Ident::new_no_span(x.into())).unwrap(), - is_absolute: true, + callpath_type: CallPathType::Full, } } @@ -309,7 +329,7 @@ impl CallPath { CallPath { prefixes: self.prefixes[0..self.prefixes.len() - 1].to_vec(), suffix: self.prefixes.last().unwrap().clone(), - is_absolute: self.is_absolute, + callpath_type: self.callpath_type, } } } @@ -319,10 +339,15 @@ impl CallPath { if self.prefixes.is_empty() { self.clone() } else { + let new_callpath_type = match self.callpath_type { + CallPathType::RelativeToPackageRoot + | CallPathType::Ambiguous => CallPathType::Ambiguous, + CallPathType::Full => CallPathType::RelativeToPackageRoot, + }; CallPath { prefixes: self.prefixes[1..self.prefixes.len()].to_vec(), suffix: self.suffix.clone(), - is_absolute: self.is_absolute, + callpath_type: new_callpath_type, } } } @@ -342,128 +367,13 @@ impl CallPath { /// before the identifier is added to the environment. pub fn ident_to_fullpath(suffix: Ident, namespace: &Namespace) -> CallPath { let mut res: Self = suffix.clone().into(); - res.prefixes.push(namespace.root_module().name().clone()); - for mod_path in namespace.mod_path() { + for mod_path in namespace.current_mod_path() { res.prefixes.push(mod_path.clone()) } - res.is_absolute = true; + res.callpath_type = CallPathType::Full; res } - /// Convert a given [CallPath] to a symbol to a full [CallPath] from the root of the project - /// in which the symbol is declared. For example, given a path `pkga::SOME_CONST` where `pkga` - /// is an _internal_ library of a package named `my_project`, the corresponding call path is - /// `my_project::pkga::SOME_CONST`. - /// - /// Paths to _external_ libraries such `std::lib1::lib2::my_obj` are considered full already - /// and are left unchanged since `std` is a root of the package `std`. - pub fn to_fullpath(&self, engines: &Engines, namespace: &Namespace) -> CallPath { - if self.is_absolute { - return self.clone(); - } - - if self.prefixes.is_empty() { - // Given a path to a symbol that has no prefixes, discover the path to the symbol as a - // combination of the package name in which the symbol is defined and the path to the - // current submodule. - let mut synonym_prefixes = vec![]; - let mut is_external = false; - let mut is_absolute = false; - - if let Some(mod_path) = namespace.program_id(engines).read(engines, |m| { - if m.current_items().symbols().contains_key(&self.suffix) { - None - } else if let Some((_, path, _, _)) = m - .current_items() - .use_item_synonyms - .get(&self.suffix) - .cloned() - { - Some(path) - } else if let Some(paths_and_decls) = m - .current_items() - .use_glob_synonyms - .get(&self.suffix) - .cloned() - { - if paths_and_decls.len() == 1 { - Some(paths_and_decls[0].0.clone()) - } else { - None - } - } else { - None - } - }) { - synonym_prefixes.clone_from(&mod_path); - is_absolute = true; - let submodule = namespace - .module(engines) - .submodule(engines, &[mod_path[0].clone()]); - if let Some(submodule) = submodule { - is_external = submodule.read(engines, |m| m.is_external); - } - } - - let mut prefixes: Vec = vec![]; - - if !is_external { - prefixes.push(namespace.root_module().name().clone()); - - if !is_absolute { - for mod_path in namespace.mod_path() { - prefixes.push(mod_path.clone()); - } - } - } - - prefixes.extend(synonym_prefixes); - - CallPath { - prefixes, - suffix: self.suffix.clone(), - is_absolute: true, - } - } else if let Some(m) = namespace - .module(engines) - .submodule(engines, &[self.prefixes[0].clone()]) - { - // If some prefixes are already present, attempt to complete the path by adding the - // package name and the path to the current submodule. - // - // If the path starts with an external module (i.e. a module that is imported in - // `Forc.toml`), then do not change it since it's a complete path already. - if m.read(engines, |m| m.is_external) { - CallPath { - prefixes: self.prefixes.clone(), - suffix: self.suffix.clone(), - is_absolute: true, - } - } else { - let mut prefixes: Vec = vec![]; - prefixes.push(namespace.root_module().name().clone()); - - for mod_path in namespace.mod_path() { - prefixes.push(mod_path.clone()); - } - - prefixes.extend(self.prefixes.clone()); - - CallPath { - prefixes, - suffix: self.suffix.clone(), - is_absolute: true, - } - } - } else { - CallPath { - prefixes: self.prefixes.clone(), - suffix: self.suffix.clone(), - is_absolute: true, - } - } - } - /// Convert a given [CallPath] into a call path suitable for a `use` statement. /// /// For example, given a path `pkga::SOME_CONST` where `pkga` is an _internal_ library of a package named @@ -474,10 +384,149 @@ impl CallPath { let converted = self.to_fullpath(engines, namespace); if let Some(first) = converted.prefixes.first() { - if namespace.root_module().name() == first { + if namespace.current_package_name() == first { return converted.lshift(); } } converted } } + +impl CallPath { + /// Convert a given [CallPath] to a symbol to a full [CallPath] from the root of the project + /// in which the symbol is declared. For example, given a path `pkga::SOME_CONST` where `pkga` + /// is an _internal_ library of a package named `my_project`, the corresponding call path is + /// `my_project::pkga::SOME_CONST`. + /// + /// Paths to _external_ libraries such `std::lib1::lib2::my_obj` are considered full already + /// and are left unchanged since `std` is a root of the package `std`. + pub fn to_fullpath(&self, engines: &Engines, namespace: &Namespace) -> CallPath { + match self.callpath_type { + CallPathType::Full => self.clone(), + CallPathType::RelativeToPackageRoot => { + let mut prefixes = vec!(); + for ident in self.prefixes.iter() { + prefixes.push(ident.clone()); + } + Self { + prefixes, + suffix: self.suffix.clone(), + callpath_type: CallPathType::Full, + } + }, + CallPathType::Ambiguous => { +// let problem = self.suffix.as_str() == "Ord" && matches!(self.callpath_type, CallPathType::Ambiguous); + + if self.prefixes.is_empty() { +// // Given a path to a symbol that has no prefixes, discover the path to the symbol as a +// // combination of the package name in which the symbol is defined and the path to the +// // current submodule. +// // let mut synonym_prefixes = vec![]; +// // let mut is_external = false; +// // let mut is_absolute = false; +// +// if let Some(mod_path) = namespace.current_module().read(engines, |m| { +// if m.current_items().symbols().contains_key(&self.suffix) { +// // if problem { dbg!("In symbols"); }; +// None +// } else if let Some((_, path, _, _)) = m +// .current_items() +// .use_item_synonyms +// .get(&self.suffix) +// .cloned() +// { +// // if problem { dbg!("In item synonyms"); }; +// Some(path) +// } else if let Some(paths_and_decls) = m +// .current_items() +// .use_glob_synonyms +// .get(&self.suffix) +// .cloned() +// { +// // if problem { dbg!("In glob_synonyms"); }; +// if paths_and_decls.len() == 1 { +// Some(paths_and_decls[0].0.clone()) +// } else { +// None +// } +// } else { +// // if problem { dbg!("Not bound"); }; +// None +// } +// }) { +// // if problem { dbg!(&mod_path); }; +// CallPath { +// prefixes: mod_path.clone(), +// suffix: self.suffix.clone(), +// callpath_type: CallPathType::Full, +// } +// // synonym_prefixes.clone_from(&mod_path); +// // is_absolute = true; +// // is_external = namespace.module_is_external(&mod_path); +// } +// else { + CallPath { + prefixes: namespace.current_mod_path.clone(), + suffix: self.suffix.clone(), + callpath_type: CallPathType::Full, + } + +// // let mut prefixes: Vec = vec![]; +// // +// // if !is_external { +// // prefixes.push(namespace.current_package_name().clone()); +// // if problem { dbg!(&prefixes); }; +// +// // if !is_absolute { +// // for mod_path in namespace.current_mod_path() { +// // prefixes.push(mod_path.clone()); +// // } +// // } +// // if problem { dbg!(&prefixes); }; +// } +// +// // prefixes.extend(synonym_prefixes); +// +// // if problem { dbg!(&prefixes); }; +// // +// // CallPath { +// // prefixes, +// // suffix: self.suffix.clone(), +// // callpath_type: CallPathType::Full, +// // } + } else if namespace.current_module_has_submodule(&self.prefixes[0]) + || namespace.current_module_has_binding(engines, &self.prefixes[0]) + { + // The first identifier in the prefix is either a submodule of the current + // module, or is bound in the current module (typically as an enum name, where + // the suffix is a variant of the enum). + // + // The path is a qualified path relative to the current module + // + // Complete the path by prepending the package name and the path to the current module. +// let mut prefixes: Vec = vec![]; +// prefixes.push(namespace.current_package_name().clone()); +// +// for mod_path in namespace.current_mod_path() { +// prefixes.push(mod_path.clone()); +// } +// +// prefixes.extend(self.prefixes.clone()); + + CallPath { + prefixes: namespace.prepend_module_path(&self.prefixes), + suffix: self.suffix.clone(), + callpath_type: CallPathType::Full, + } + } else { + // Fully qualified path + CallPath { + prefixes: self.prefixes.clone(), + suffix: self.suffix.clone(), + callpath_type: CallPathType::Full, + } + } + }, + } + } +} diff --git a/sway-core/src/language/parsed/use_statement.rs b/sway-core/src/language/parsed/use_statement.rs index ceda688d75f..c34a37ede6b 100644 --- a/sway-core/src/language/parsed/use_statement.rs +++ b/sway-core/src/language/parsed/use_statement.rs @@ -14,9 +14,16 @@ pub struct UseStatement { pub call_path: Vec, pub span: Span, pub import_type: ImportType, - // If `is_absolute` is true, then this use statement is an absolute path from - // the project root namespace. If not, then it is relative to the current namespace. - pub is_absolute: bool, + // If `is_relative_to_package_root` is true, then this use statement is a path relative to the + // project root. For example, if the path is `::X::Y` and occurs in package `P`, then the path + // refers to the full path `P::X::Y`. + // If `is_relative_to_package_root` is false, then there are two options: + // - The path refers to a path relative to the current namespace. For example, if the path is + // `X::Y` and it occurs in a module whose path is `P::M`, then the path refers to the full + // path `P::M::X::Y`. + // - The path refers to a path in an external package. For example, the path `X::Y` refers to an + // entity `Y` in the external package `X`. + pub is_relative_to_package_root: bool, // If `reexport` is Visibility::Public, then this use statement reexports its imported binding. // If not, then the import binding is private to the importing module. pub reexport: Visibility, diff --git a/sway-core/src/language/ty/declaration/struct.rs b/sway-core/src/language/ty/declaration/struct.rs index c4dc7e3e219..b4f34eb01d9 100644 --- a/sway-core/src/language/ty/declaration/struct.rs +++ b/sway-core/src/language/ty/declaration/struct.rs @@ -10,7 +10,7 @@ use crate::{ engine_threading::*, error::module_can_be_changed, has_changes, - language::{parsed::StructDeclaration, CallPath, Visibility}, + language::{parsed::StructDeclaration, CallPath, CallPathType, Visibility}, transform, type_system::*, Namespace, @@ -155,14 +155,14 @@ pub struct StructAccessInfo { impl StructAccessInfo { pub fn get_info(engines: &Engines, struct_decl: &TyStructDecl, namespace: &Namespace) -> Self { assert!( - struct_decl.call_path.is_absolute, - "The call path of the struct declaration must always be absolute." + matches!(struct_decl.call_path.callpath_type, CallPathType::Full), + "The call path of the struct declaration must always be fully resolved." ); let struct_can_be_changed = module_can_be_changed(engines, namespace, &struct_decl.call_path.prefixes); let is_public_struct_access = - !namespace.module_is_submodule_of(engines, &struct_decl.call_path.prefixes, true); + !namespace.module_is_submodule_of(&struct_decl.call_path.prefixes, true); Self { struct_can_be_changed, diff --git a/sway-core/src/language/ty/expression/expression_variant.rs b/sway-core/src/language/ty/expression/expression_variant.rs index 9908bb09f5b..a43fa424a04 100644 --- a/sway-core/src/language/ty/expression/expression_variant.rs +++ b/sway-core/src/language/ty/expression/expression_variant.rs @@ -825,7 +825,7 @@ impl ReplaceDecls for TyExpressionVariant { let implementing_type_method_ref = ctx.find_method_for_type( handler, implementing_for_typeid, - &[], + &[ctx.namespace().current_package_name().clone()], method.name(), method.return_type.type_id, &arguments diff --git a/sway-core/src/language/ty/side_effect/use_statement.rs b/sway-core/src/language/ty/side_effect/use_statement.rs index 5d9c0cf1ca1..93aba86d361 100644 --- a/sway-core/src/language/ty/side_effect/use_statement.rs +++ b/sway-core/src/language/ty/side_effect/use_statement.rs @@ -6,9 +6,16 @@ pub struct TyUseStatement { pub call_path: Vec, pub span: Span, pub import_type: parsed::ImportType, - // If `is_absolute` is true, then this use statement is an absolute path from - // the project root namespace. If not, then it is relative to the current namespace. - pub is_absolute: bool, + // If `is_relative_to_package_root` is true, then this use statement is a path relative to the + // project root. For example, if the path is `::X::Y` and occurs in package `P`, then the path + // refers to the full path `P::X::Y`. + // If `is_relative_to_package_root` is false, then there are two options: + // - The path refers to a path relative to the current namespace. For example, if the path is + // `X::Y` and it occurs in a module whose path is `P::M`, then the path refers to the full + // path `P::M::X::Y`. + // - The path refers to a path in an external package. For example, the path `X::Y` refers to an + // entity `Y` in the external package `X`. + pub is_relative_to_package_root: bool, pub alias: Option, } diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index ac6b7d54d34..969e2acdb2b 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -548,7 +548,7 @@ pub fn parsed_to_ast( handler: &Handler, engines: &Engines, parse_program: &mut parsed::ParseProgram, - initial_namespace: &mut namespace::Root, + initial_namespace: namespace::Root, build_config: Option<&BuildConfig>, package_name: &str, retrigger_compilation: Option>, @@ -559,18 +559,21 @@ pub fn parsed_to_ast( // Build the dependency graph for the submodules. build_module_dep_graph(handler, &mut parse_program.root)?; - let namespace = Namespace::init_root(initial_namespace); + let collection_namespace = Namespace::new(handler, engines, initial_namespace.clone(), true)?; // Collect the program symbols. + let mut collection_ctx = - ty::TyProgram::collect(handler, engines, parse_program, namespace.clone())?; + ty::TyProgram::collect(handler, engines, parse_program, collection_namespace)?; + // TODO: Eliminate this cloning step? + let typecheck_namespace = Namespace::new(handler, engines, initial_namespace, true)?; // Type check the program. let typed_program_opt = ty::TyProgram::type_check( handler, engines, parse_program, - &mut collection_ctx, - namespace, + &mut collection_ctx, + typecheck_namespace, package_name, build_config, experimental, @@ -661,7 +664,7 @@ pub fn parsed_to_ast( &mut ctx, &mut md_mgr, module, - typed_program.root.namespace.module(engines), + typed_program.root.namespace.current_module(), ) { handler.emit_err(e); } @@ -713,7 +716,7 @@ pub fn compile_to_ast( handler: &Handler, engines: &Engines, input: Arc, - initial_namespace: &mut namespace::Root, + initial_namespace: namespace::Root, build_config: Option<&BuildConfig>, package_name: &str, retrigger_compilation: Option>, @@ -807,7 +810,7 @@ pub fn compile_to_asm( handler: &Handler, engines: &Engines, input: Arc, - initial_namespace: &mut namespace::Root, + initial_namespace: namespace::Root, build_config: &BuildConfig, package_name: &str, experimental: ExperimentalFeatures, @@ -974,7 +977,7 @@ pub fn compile_to_bytecode( handler: &Handler, engines: &Engines, input: Arc, - initial_namespace: &mut namespace::Root, + initial_namespace: namespace::Root, build_config: &BuildConfig, source_map: &mut SourceMap, package_name: &str, 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 330b8e4e4e9..fc1122dd223 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -51,7 +51,7 @@ impl ty::TyCodeBlock { ctx.engines.te().clear_unifications(); ctx.namespace() - .module(ctx.engines) + .current_module() .current_lexical_scope() .items .clear_symbols_unique_while_collecting_unifications(); 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 bb0bc9e2fb8..2ef4045fca3 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -82,6 +82,8 @@ impl ty::TyAbiDecl { let self_type_param = TypeParameter::new_self_type(ctx.engines, name.span()); let self_type_id = self_type_param.type_id; + let mod_path = ctx.namespace().current_mod_path().clone(); + // A temporary namespace for checking within this scope. ctx.with_abi_mode(AbiMode::ImplAbiFn(name.clone(), None)) .with_self_type(Some(self_type_id)) @@ -103,13 +105,13 @@ impl ty::TyAbiDecl { let mut new_interface_surface = vec![]; let mut ids: HashSet = HashSet::default(); - let error_on_shadowing_superabi_method = |method_name: &Ident, ctx: &mut TypeCheckContext| { if let Ok(superabi_impl_method_ref) = ctx.find_method_for_type( &Handler::default(), self_type_id, - &[], + //&[], <---- This doesn't look right + &mod_path, &method_name.clone(), ctx.type_annotation(), &Default::default(), @@ -274,6 +276,8 @@ impl ty::TyAbiDecl { (false, Span::dummy()) }; + let mod_path = ctx.namespace().current_mod_path().clone(); + handler.scope(|handler| { for item in interface_surface.iter() { match item { @@ -284,7 +288,8 @@ impl ty::TyAbiDecl { if let Ok(superabi_method_ref) = ctx.find_method_for_type( &Handler::default(), type_id, - &[], + //&[], + &mod_path, &method.name.clone(), ctx.type_annotation(), &Default::default(), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs index 55ef6a25e79..3ed822a5d41 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs @@ -422,7 +422,7 @@ where engines: &Engines, decl: &TyDecl, ) -> Option<(Option, Option)> { - if self.ctx.namespace.root().module.name().as_str() == "core" { + if self.ctx.namespace.current_package_name().as_str() == "core" { return Some((None, None)); } @@ -457,7 +457,7 @@ where engines: &Engines, decl: &TyDecl, ) -> Option<(Option, Option)> { - if self.ctx.namespace.root().module.name().as_str() == "core" { + if self.ctx.namespace.current_package_name().as_str() == "core" { return Some((None, None)); } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs index 6c9f5e7f404..b052081b289 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs @@ -15,7 +15,7 @@ use crate::{ language::{ parsed::*, ty::{self, TyConfigurableDecl, TyExpression}, - CallPath, + CallPath, CallPathType, }, semantic_analysis::*, EnforceTypeArguments, Engines, SubstTypes, TypeArgument, TypeBinding, TypeCheckTypeBinding, @@ -122,7 +122,7 @@ impl ty::TyConfigurableDecl { "abi_decode_in_place".into(), value_span.clone(), ), - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, type_arguments: crate::TypeArgs::Regular(vec![TypeArgument { type_id: type_ascription.type_id, 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 663891261bd..6b670806d12 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -282,7 +282,7 @@ impl TyDecl { if let ty::TyTraitItem::Fn(f) = i { let decl = engines.de().get(f.id()); let collecting_unifications = ctx.collecting_unifications(); - let _ = ctx.namespace.module_mut(ctx.engines()).write(engines, |m| { + let _ = ctx.namespace.current_module_mut().write(engines, |m| { m.current_items_mut().insert_typed_symbol( handler, engines, @@ -506,7 +506,7 @@ impl TyDecl { // declarations are not allowed ctx.namespace_mut() - .module_mut(engines) + .current_module_mut() .write(engines, |m| { m.current_items_mut() .set_storage_declaration(handler, decl_ref.clone()) 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 52ede5c3343..8b0eff9f273 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -82,6 +82,19 @@ impl ty::TyFunctionDecl { kind, .. } = fn_decl; + +// let current_mod_path = ctx.namespace().current_mod_path(); +// let problem = name.as_str() == "from_parts" +// && current_mod_path.len() == 2 +// && current_mod_path[0].as_str() == "core" +// && current_mod_path[1].as_str() == "raw_slice" +// ; +// +// if problem { +// dbg!(¶meters); +// dbg!(&visibility); +// } + let mut return_type = fn_decl.return_type.clone(); let type_engine = ctx.engines.te(); 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 8d88a8989d8..aab0fe20a32 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 @@ -160,6 +160,7 @@ impl TyImplSelfOrTrait { .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) .with_self_type(Some(implementing_for.type_id)); +// dbg!(&trait_name); let impl_trait = match ctx .namespace() .resolve_call_path_typed(handler, engines, &trait_name, ctx.self_type()) @@ -353,8 +354,11 @@ impl TyImplSelfOrTrait { } => call_path.call_path.suffix.clone(), _ => Ident::new_with_override("r#Self".into(), implementing_for.span()), }; +// let problem = suffix.as_str() == "Bytes"; let trait_name = CallPath::ident_to_fullpath(suffix, ctx.namespace()); - +// if problem { +// dbg!(&trait_name); +// } // Type check the type parameters. let new_impl_type_parameters = TypeParameter::type_check_type_params( handler, @@ -423,6 +427,7 @@ impl TyImplSelfOrTrait { match item { ImplItem::Fn(fn_decl_id) => { let fn_decl = engines.pe().get_function(fn_decl_id); +// if problem { dbg!(&fn_decl); }; let fn_decl = match ty::TyFunctionDecl::type_check_signature( handler, ctx.by_ref(), @@ -686,7 +691,7 @@ fn type_check_trait_implementation( // Check to see if the type that we are implementing for implements the // supertraits of this trait. ctx.namespace_mut() - .module_mut(engines) + .current_module_mut() .write(engines, |m| { m.current_items_mut() .implemented_traits @@ -1571,6 +1576,8 @@ fn handle_supertraits( continue; } + //dbg!(&supertrait.name); + match ctx .namespace() // Use the default Handler to avoid emitting the redundant SymbolNotFound error. @@ -1627,6 +1634,7 @@ fn handle_supertraits( // we allow ABIs as superABIs now } _ => { +// println!("impl_trait"); handler.emit_err(CompileError::TraitNotFound { name: supertrait.name.to_string(), span: supertrait.name.span(), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs index d74932eea9e..6a52b729b91 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs @@ -163,6 +163,8 @@ pub(crate) fn insert_supertraits_into_namespace( }); } _ => { +// println!("supertrait"); +// dbg!(&supertrait.name); handler.emit_err(CompileError::TraitNotFound { name: supertrait.name.to_string(), span: supertrait.name.span(), 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 9a0ed2942eb..b3a19c07450 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -164,6 +164,8 @@ impl TyTraitDecl { // insert placeholder functions representing the interface surface // to allow methods to use those functions + // let path = CallPath::ident_to_fullpath(name.clone(), ctx.namespace); + // dbg!(path); ctx.insert_trait_implementation( handler, CallPath::ident_to_fullpath(name.clone(), ctx.namespace), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs index cd9bff70750..040c76b9158 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs @@ -85,7 +85,7 @@ impl ty::TyVariableDecl { if !ctx.code_block_first_pass() { let previous_symbol = ctx .namespace() - .module(engines) + .current_module() .current_items() .check_symbols_unique_while_collecting_unifications(&var_decl.name.clone()) .ok(); 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 fddb0ee7b21..8e72541f5f1 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 @@ -10,7 +10,7 @@ use crate::{ language::{ parsed::*, ty::{self, StructAccessInfo, TyDecl, TyScrutinee, TyStructDecl, TyStructField}, - CallPath, + CallPath, CallPathType, }, semantic_analysis::{TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext}, type_system::*, @@ -90,7 +90,7 @@ impl TyScrutinee { CallPath { prefixes: vec![], suffix: ident.clone(), - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, Scrutinee::Tuple { elems: vec![], @@ -437,7 +437,7 @@ fn type_check_struct( instantiation_call_path: CallPath { prefixes: vec![], suffix: struct_name, - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, }, }; @@ -493,7 +493,7 @@ fn type_check_enum( let enum_callpath = CallPath { suffix: enum_name, prefixes, - is_absolute: call_path.is_absolute, + callpath_type: call_path.callpath_type, }; // find the enum definition from the name let unknown_decl = ctx.namespace().resolve_call_path_typed( 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 51672758fba..628aa095f22 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 @@ -89,7 +89,7 @@ impl ty::TyExpression { span: span.clone(), } .to_var_name(), - is_absolute: true, + callpath_type: CallPathType::Full, }; let mut method_name_binding = TypeBinding { inner: MethodName::FromTrait { @@ -291,22 +291,32 @@ impl ty::TyExpression { Ok(Self::type_check_literal(engines, lit.clone(), span)) } ExpressionKind::AmbiguousVariableExpression(name) => { - let call_path = CallPath { - prefixes: vec![], - suffix: name.clone(), - is_absolute: false, - }; if matches!( ctx.namespace() - .resolve_call_path_typed( - &Handler::default(), - engines, - &call_path, - ctx.self_type() - ) + .resolve_symbol_typed( + &Handler::default(), + engines, + &name, + ctx.self_type(), + ) .ok(), Some(ty::TyDecl::EnumVariantDecl { .. }) ) { + let call_path = CallPath { + prefixes: vec![], + suffix: name.clone(), + callpath_type: CallPathType::Ambiguous, + };//.to_fullpath(engines, ctx.namespace()); + +// let problem = +// name.as_str() == "None" +// && ctx.namespace().current_mod_path().len() == 2 +// && ctx.namespace().current_mod_path()[0].as_str() == "std" +// && ctx.namespace().current_mod_path()[1].as_str() == "vec"; +// if problem { +// dbg!(&call_path); +// }; + Self::type_check_delineated_path( handler, ctx.by_ref(), @@ -1210,20 +1220,20 @@ impl ty::TyExpression { if !ctx .namespace() - .program_id(engines) + .current_module() .read(engines, |m| m.current_items().has_storage_declared()) { return Err(handler.emit_err(CompileError::NoDeclaredStorage { span: span.clone() })); } - let storage_fields = ctx.namespace().program_id(engines).read(engines, |m| { + let storage_fields = ctx.namespace().current_module().read(engines, |m| { m.current_items() .get_storage_field_descriptors(handler, decl_engine) })?; // Do all namespace checking here! let (storage_access, mut access_type) = - ctx.namespace().program_id(engines).read(engines, |m| { + ctx.namespace().current_module().read(engines, |m| { m.current_items().apply_storage_load( handler, ctx.engines, @@ -1244,7 +1254,7 @@ impl ty::TyExpression { let storage_key_ident = Ident::new_with_override("StorageKey".into(), span.clone()); // Search for the struct declaration with the call path above. - let storage_key_decl = ctx.namespace().root().resolve_symbol( + let storage_key_decl = ctx.namespace().resolve_symbol_with_path( handler, engines, &storage_key_mod_path, @@ -1326,7 +1336,7 @@ impl ty::TyExpression { CallPath { prefixes, suffix: AmbiguousSuffix { before, suffix }, - is_absolute, + callpath_type, }, type_arguments, span: path_span, @@ -1351,7 +1361,7 @@ impl ty::TyExpression { call_path: CallPath { prefixes: prefixes_and_before.clone(), suffix: prefixes_and_before_last.clone(), - is_absolute, + callpath_type, }, qualified_path_root: qualified_path_root.map(Box::new), }; @@ -1368,7 +1378,7 @@ impl ty::TyExpression { inner: CallPath { prefixes, suffix: (type_info, prefixes_and_before_last), - is_absolute, + callpath_type, }, }, method_name: suffix, @@ -1405,8 +1415,9 @@ impl ty::TyExpression { let call_path = CallPath { prefixes, suffix, - is_absolute, - }; + callpath_type, + }.to_fullpath(&engines, ctx.namespace()); + if matches!( ctx.namespace().resolve_call_path_typed( &Handler::default(), @@ -1453,11 +1464,24 @@ impl ty::TyExpression { let mut path = Vec::with_capacity(prefixes.len() + 1); path.extend(prefixes.iter().cloned()); path.push(before.inner.clone()); + +// let mod_path = ctx.namespace.current_mod_path(); +// let problem = before.inner.as_str() == "codec" +// && mod_path.len() == 2 +// && mod_path[0].as_str() == "std" +// && mod_path[1].as_str() == "inputs"; +// if problem { +// dbg!(&path); +// } + let not_module = { let h = Handler::default(); + // The path may be relative to the current module, + // or may be a full path ctx.namespace() - .program_id(engines) - .read(engines, |m| m.lookup_submodule(&h, engines, &path).is_err()) + .current_module() + .read(engines, |m| m.lookup_submodule(&h, &path).is_err()) + && ctx.namespace().module_from_absolute_path(&path).is_none() }; // Not a module? Not a `Enum::Variant` either? @@ -1466,7 +1490,7 @@ impl ty::TyExpression { let probe_call_path = CallPath { prefixes: prefixes.clone(), suffix: before.inner.clone(), - is_absolute, + callpath_type, }; ctx.namespace() .resolve_call_path_typed( @@ -1500,8 +1524,8 @@ impl ty::TyExpression { inner: CallPath { prefixes, suffix: (type_info, type_name), - is_absolute, - }, + callpath_type, + }.to_fullpath(engines, ctx.namespace()), }, method_name: suffix, }, @@ -1534,7 +1558,7 @@ impl ty::TyExpression { call_path: CallPath { prefixes: path, suffix, - is_absolute, + callpath_type, }, qualified_path_root: None, }, @@ -1559,11 +1583,13 @@ impl ty::TyExpression { let mut is_module = false; let mut maybe_function: Option<(DeclRefFunction, _)> = None; - let mut maybe_enum: Option<(DeclRefEnum, _, _, _)> = None; + let mut maybe_enum_variant_with_enum_name: Option<(DeclRefEnum, _, _, _)> = None; + let mut maybe_enum_variant_without_enum_name: Option<(DeclRefEnum, _, _, _)> = None; let module_probe_handler = Handler::default(); let function_probe_handler = Handler::default(); - let enum_probe_handler = Handler::default(); + let variant_with_enum_probe_handler = Handler::default(); + let variant_without_enum_probe_handler = Handler::default(); let const_probe_handler = Handler::default(); if unknown_call_path_binding @@ -1572,14 +1598,15 @@ impl ty::TyExpression { .is_none() { // Check if this could be a module + // TODO: This is no longer correct - an absolute path to an external module can no + // longer be looked up as a submodule of the current module is_module = { let call_path_binding = unknown_call_path_binding.clone(); ctx.namespace() - .program_id(ctx.engines()) + .current_module() .read(ctx.engines(), |m| { m.lookup_submodule( &module_probe_handler, - ctx.engines(), &[ call_path_binding.inner.call_path.prefixes.clone(), vec![call_path_binding.inner.call_path.suffix.clone()], @@ -1608,18 +1635,70 @@ impl ty::TyExpression { .map(|(fn_ref, _, _)| (fn_ref, call_path_binding)) }; - // Check if this could be an enum - maybe_enum = { + // Check if this could be an enum variant preceeded by its enum name. + // For instance, the enum `Option` contains two variants, `None` and `Some`. + // The full path for `None` would be current_mod_path::Option::None. + maybe_enum_variant_with_enum_name = { + let call_path_binding = unknown_call_path_binding.clone(); + let variant_name = call_path_binding.inner.call_path.suffix.clone(); + let enum_call_path = call_path_binding.inner.call_path.to_fullpath(ctx.engines(), ctx.namespace()).rshift(); + +// let mod_path = ctx.namespace().current_mod_path(); +// let problem = variant_name.as_str() == "Ok" +// && mod_path.len() == 2 +// && mod_path[0].as_str() == "std" +// && mod_path[1].as_str() == "option" +// ; +// if problem { +// dbg!("maybe enum"); +// dbg!(&unknown_call_path_binding); +// dbg!(&enum_call_path); +// } + + let mut call_path_binding = TypeBinding { + inner: enum_call_path, + type_arguments: call_path_binding.type_arguments, + span: call_path_binding.span, + }; + TypeBinding::type_check(&mut call_path_binding, &variant_with_enum_probe_handler, ctx.by_ref()) + .ok() + .map(|(enum_ref, _, ty_decl)| { + ( + enum_ref, + variant_name, + call_path_binding, + ty_decl.expect("type_check for TyEnumDecl should always return TyDecl"), + ) + }) + }; + + // Check if this could be an enum variant without the enum name. This can happen when + // the variants are imported using a star import + // For instance, `use Option::*` binds the name `None` in the current module, so the + // full path would be current_mod_path::None rather than current_mod_path::Option::None. + maybe_enum_variant_without_enum_name = { let call_path_binding = unknown_call_path_binding.clone(); let variant_name = call_path_binding.inner.call_path.suffix.clone(); - let enum_call_path = call_path_binding.inner.call_path.rshift(); + let enum_call_path = call_path_binding.inner.call_path.to_fullpath(ctx.engines(), ctx.namespace()); + +// let mod_path = ctx.namespace().current_mod_path(); +// let problem = variant_name.as_str() == "Ok" +// && mod_path.len() == 2 +// && mod_path[0].as_str() == "std" +// && mod_path[1].as_str() == "option" +// ; +// if problem { +// dbg!("maybe enum"); +// dbg!(&unknown_call_path_binding); +// dbg!(&enum_call_path); +// } let mut call_path_binding = TypeBinding { inner: enum_call_path, type_arguments: call_path_binding.type_arguments, span: call_path_binding.span, }; - TypeBinding::type_check(&mut call_path_binding, &enum_probe_handler, ctx.by_ref()) + TypeBinding::type_check(&mut call_path_binding, &variant_without_enum_probe_handler, ctx.by_ref()) .ok() .map(|(enum_ref, _, ty_decl)| { ( @@ -1637,14 +1716,33 @@ impl ty::TyExpression { { Self::probe_const_decl(&unknown_call_path_binding, &mut ctx, &const_probe_handler) }; // compare the results of the checks - let exp = match (is_module, maybe_function, maybe_enum, maybe_const) { + let exp = match (is_module, maybe_function, maybe_enum_variant_with_enum_name, maybe_enum_variant_without_enum_name, maybe_const) { + ( + false, + None, + Some((enum_ref, variant_name, call_path_binding, call_path_decl)), + None, + None, + ) => { + handler.append(variant_with_enum_probe_handler); + instantiate_enum( + handler, + ctx, + enum_ref, + variant_name, + args, + call_path_binding, + call_path_decl, + )? + } ( false, None, + None, Some((enum_ref, variant_name, call_path_binding, call_path_decl)), None, ) => { - handler.append(enum_probe_handler); + handler.append(variant_without_enum_probe_handler); instantiate_enum( handler, ctx, @@ -1655,7 +1753,7 @@ impl ty::TyExpression { call_path_decl, )? } - (false, Some((fn_ref, call_path_binding)), None, None) => { + (false, Some((fn_ref, call_path_binding)), None, None, None) => { handler.append(function_probe_handler); // In case `foo::bar::::baz(...)` throw an error. if let TypeArgs::Prefix(_) = call_path_binding.type_arguments { @@ -1675,14 +1773,14 @@ impl ty::TyExpression { span, )? } - (true, None, None, None) => { + (true, None, None, None, None) => { handler.append(module_probe_handler); return Err(handler.emit_err(CompileError::ModulePathIsNotAnExpression { module_path: unknown_call_path_binding.inner.call_path.to_string(), span, })); } - (false, None, None, Some((const_ref, call_path_binding))) => { + (false, None, None, None, Some((const_ref, call_path_binding))) => { handler.append(const_probe_handler); if !call_path_binding.type_arguments.to_vec().is_empty() { // In case `foo::bar::CONST::` throw an error. @@ -1696,7 +1794,17 @@ impl ty::TyExpression { } instantiate_constant_expression(ctx, const_ref, call_path_binding) } - (false, None, None, None) => { + (false, None, None, None, None) => { +// let mod_path = ctx.namespace().current_mod_path(); +// let problem = unknown_call_path_binding.inner.call_path.suffix.as_str() == "codec" +// && mod_path.len() == 2 +// && mod_path[0].as_str() == "std" +// && mod_path[1].as_str() == "inputs" +// ; +// if problem { +// dbg!("typecheck delineated path"); +// dbg!(&unknown_call_path_binding); +// } return Err(handler.emit_err(CompileError::SymbolNotFound { name: unknown_call_path_binding.inner.call_path.suffix.clone(), span: unknown_call_path_binding.inner.call_path.suffix.span(), @@ -2425,7 +2533,7 @@ impl ty::TyExpression { let indices = indices.into_iter().rev().collect::>(); let (ty_of_field, _ty_of_parent) = - ctx.namespace().program_id(engines).read(engines, |m| { + ctx.namespace().current_module().read(engines, |m| { m.current_items().find_subfield_type( handler, ctx.engines(), @@ -2837,7 +2945,7 @@ fn check_asm_block_validity( &CallPath { prefixes: vec![], suffix: sway_types::BaseIdent::new(span.clone()), - is_absolute: true, + callpath_type: CallPathType::Ambiguous, }, None, ); 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 3c118c43536..330aa42dde0 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 @@ -349,19 +349,19 @@ pub(crate) fn type_check_method_application( CallPath { prefixes, suffix: method_name, - is_absolute: call_path_binding.inner.is_absolute, + callpath_type: call_path_binding.inner.callpath_type, } } MethodName::FromModule { method_name } => CallPath { prefixes: vec![], suffix: method_name, - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, MethodName::FromTrait { call_path } => call_path, MethodName::FromQualifiedPathRoot { method_name, .. } => CallPath { prefixes: vec![], suffix: method_name, - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, }; @@ -465,7 +465,7 @@ pub(crate) fn type_check_method_application( inner: CallPath { prefixes: vec![], suffix: Ident::new_no_span("contract_call".into()), - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, type_arguments: TypeArgs::Regular(vec![ TypeArgument { @@ -541,8 +541,7 @@ pub(crate) fn type_check_method_application( .type_id .extract_inner_types(engines, IncludeSelf::Yes) { - let handler = Handler::default(); - ctx.impls_import(&handler, engines, type_id); + ctx.impls_import(engines, type_id); } let args = old_arguments.iter().skip(1).cloned().collect(); @@ -815,7 +814,15 @@ pub(crate) fn resolve_method_name( call_path_binding, method_name, } => { +// dbg!("FromType"); // type check the call path +// let mod_path = ctx.namespace().current_mod_path(); +// let problem = mod_path.len() == 2 +// && mod_path[0].as_str() == "std" +// && mod_path[1].as_str() == "inputs"; +// if problem { +// dbg!(&call_path_binding); +// } let type_id = call_path_binding .type_check_with_type_info(handler, &mut ctx) .unwrap_or_else(|err| { @@ -823,14 +830,11 @@ pub(crate) fn resolve_method_name( }); // find the module that the symbol is in - let type_info_prefix = ctx - .namespace() - .prepend_module_path(&call_path_binding.inner.prefixes); - ctx.namespace().lookup_submodule_from_absolute_path( - handler, - engines, - &type_info_prefix, - )?; +// let type_info_prefix = ctx +// .namespace() + // .prepend_module_path(&call_path_binding.inner.prefixes); + let type_info_prefix = call_path_binding.inner.to_fullpath(engines, ctx.namespace()).prefixes.clone(); + ctx.namespace().require_module_from_absolute_path(handler, &type_info_prefix)?; // find the method let decl_ref = ctx.find_method_for_type( @@ -847,21 +851,26 @@ pub(crate) fn resolve_method_name( (decl_ref, type_id) } MethodName::FromTrait { call_path } => { +// dbg!("FromTrait"); // find the module that the symbol is in - let module_path = if !call_path.is_absolute { - ctx.namespace().prepend_module_path(&call_path.prefixes) - } else { - let mut module_path = call_path.prefixes.clone(); - if let (Some(root_mod), root_name) = ( - module_path.first().cloned(), - ctx.namespace().root_module().name().clone(), - ) { - if root_mod.as_str() == root_name.as_str() { - module_path.remove(0); - } - } - module_path - }; + let module_path = + match call_path.callpath_type { + CallPathType::RelativeToPackageRoot => { + let mut path = vec!(ctx.namespace().current_package_name().clone()); + for ident in call_path.prefixes.iter() { + path.push(ident.clone()) + } + path + }, + CallPathType::Full => call_path.prefixes.clone(), + CallPathType::Ambiguous => { + if ctx.namespace().current_module().submodules().contains_key(call_path.prefixes.first().unwrap().as_str()) { + ctx.namespace().prepend_module_path(&call_path.prefixes) + } else { + call_path.prefixes.clone() + } + } + }; // find the type of the first argument let type_id = arguments_types @@ -884,8 +893,10 @@ pub(crate) fn resolve_method_name( (decl_ref, type_id) } MethodName::FromModule { method_name } => { +// dbg!("FromModule"); // find the module that the symbol is in - let module_path = ctx.namespace().prepend_module_path(vec![]); + let module_path = ctx.namespace().current_mod_path().clone(); +// dbg!(&module_path); // find the type of the first argument let type_id = arguments_types @@ -912,11 +923,12 @@ pub(crate) fn resolve_method_name( as_trait, method_name, } => { +// dbg!("FromQualifiedPathRoot"); // type check the call path let type_id = ty.type_id; // find the module that the symbol is in - let module_path = ctx.namespace().prepend_module_path(vec![]); + let module_path = ctx.namespace().current_mod_path().clone(); // find the method let decl_ref = ctx.find_method_for_type( diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index 1d84a623fbd..a985a5945ee 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -78,8 +78,7 @@ pub(crate) fn struct_instantiation( // find the module that the struct decl is in let type_info_prefix = ctx.namespace().prepend_module_path(prefixes); - ctx.namespace() - .lookup_submodule_from_absolute_path(handler, engines, &type_info_prefix)?; + ctx.namespace().require_module_from_absolute_path(handler, &type_info_prefix)?; // resolve the type of the struct decl let type_id = ctx @@ -337,7 +336,7 @@ fn collect_struct_constructors( // Also, strictly speaking, we could also have public module functions that create structs, // but that would be a way too much of suggestions, and moreover, it is also not a design pattern/guideline // that we wish to encourage. - namespace.program_id(engines).read(engines, |m| { + namespace.current_module().read(engines, |m| { m.current_items() .get_items_for_type(engines, struct_type_id) .iter() diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 3a6ea5f2153..21814dc6fbd 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -55,13 +55,13 @@ impl ty::TyAstNode { let node = ty::TyAstNode { content: match node.content.clone() { AstNodeContent::UseStatement(stmt) => { - handle_use_statement(&mut ctx, engines, &stmt, handler); + handle_use_statement(&mut ctx, &stmt, handler); ty::TyAstNodeContent::SideEffect(ty::TySideEffect { side_effect: ty::TySideEffectVariant::UseStatement(ty::TyUseStatement { alias: stmt.alias, call_path: stmt.call_path, span: stmt.span, - is_absolute: stmt.is_absolute, + is_relative_to_package_root: stmt.is_relative_to_package_root, import_type: stmt.import_type, }), }) @@ -140,31 +140,13 @@ fn collect_use_statement( ctx: &mut SymbolCollectionContext, stmt: &UseStatement, ) { - let mut is_external = false; - if let Some(submodule) = ctx - .namespace - .module(engines) - .submodule(engines, &[stmt.call_path[0].clone()]) - { - is_external |= submodule.read(engines, |m| m.is_external); - } - // We create an inner module for each module being processed during the collection. - // This does not play well with the existing way we use to lookup an external module. - // So check again starting from the root to make sure we find the right module. - // Clean this up once paths are normalized before collection and we can just rely on - // absolute paths. - if let Some(submodule) = ctx - .namespace - .root_module() - .submodule(engines, &[stmt.call_path[0].clone()]) - { - is_external |= submodule.read(engines, |m| m.is_external); - } - let path = if is_external || stmt.is_absolute { - stmt.call_path.clone() - } else { - ctx.namespace.prepend_module_path(&stmt.call_path) - }; + let path = ctx.namespace.parsed_path_to_full_path(&stmt.call_path, stmt.is_relative_to_package_root); +// let is_external = !ctx.namespace.current_module_has_submodule(&stmt.call_path[0]); +// let path = if is_external || stmt.is_absolute { +// stmt.call_path.clone() +// } else { +// ctx.namespace.prepend_module_path(&stmt.call_path) +// }; let _ = match stmt.import_type { ImportType::Star => { // try a standard starimport first @@ -247,23 +229,18 @@ fn collect_use_statement( // To be removed once TypeCheckContext is ported to use SymbolCollectionContext. fn handle_use_statement( ctx: &mut TypeCheckContext<'_>, - engines: &Engines, stmt: &UseStatement, handler: &Handler, ) { - let mut is_external = false; - if let Some(submodule) = ctx - .namespace() - .module(engines) - .submodule(engines, &[stmt.call_path[0].clone()]) - { - is_external = submodule.read(engines, |m| m.is_external); - } - let path = if is_external || stmt.is_absolute { - stmt.call_path.clone() - } else { - ctx.namespace().prepend_module_path(&stmt.call_path) - }; + let path = ctx.namespace.parsed_path_to_full_path(&stmt.call_path, stmt.is_relative_to_package_root); +// let is_external = !ctx +// .namespace() +// .current_module_has_submodule(&stmt.call_path[0]); +// let path = if is_external || stmt.is_absolute { +// stmt.call_path.clone() +// } else { +// ctx.namespace().prepend_module_path(&stmt.call_path) +// }; let _ = match stmt.import_type { ImportType::Star => { // try a standard starimport first diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index 8acdf1cac09..f11517d8d90 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -687,17 +687,18 @@ impl ty::TySubmodule { visibility, } = submodule; parent_ctx.enter_submodule( - engines, + handler, + engines, mod_name, *visibility, module.span.clone(), |submod_ctx| ty::TyModule::collect(handler, engines, submod_ctx, module), - ) + )? } pub fn type_check( handler: &Handler, - parent_ctx: TypeCheckContext, + mut parent_ctx: TypeCheckContext, engines: &Engines, mod_name: ModName, kind: TreeType, @@ -709,13 +710,13 @@ impl ty::TySubmodule { mod_name_span, visibility, } = submodule; - parent_ctx.enter_submodule(mod_name, *visibility, module.span.clone(), |submod_ctx| { + parent_ctx.enter_submodule(handler, mod_name, *visibility, module.span.clone(), |submod_ctx| { let module_res = ty::TyModule::type_check(handler, submod_ctx, engines, kind, module, build_config); module_res.map(|module| ty::TySubmodule { module, mod_name_span: mod_name_span.clone(), }) - }) + })? } } diff --git a/sway-core/src/semantic_analysis/namespace/contract_helpers.rs b/sway-core/src/semantic_analysis/namespace/contract_helpers.rs index af8a84cbac6..ec665167701 100644 --- a/sway-core/src/semantic_analysis/namespace/contract_helpers.rs +++ b/sway-core/src/semantic_analysis/namespace/contract_helpers.rs @@ -4,66 +4,168 @@ use sway_error::{ handler::{ErrorEmitted, Handler}, }; use sway_parse::{lex, Parser}; -use sway_types::{Ident, Spanned}; +use sway_types::{constants::CONTRACT_ID, Spanned}; use crate::{ language::{ parsed::{AstNode, AstNodeContent, Declaration, ExpressionKind}, ty::{TyAstNode, TyAstNodeContent}, - Visibility, }, - semantic_analysis::{symbol_collection_context::SymbolCollectionContext, TypeCheckContext}, + semantic_analysis::{symbol_collection_context::SymbolCollectionContext, TypeCheckContext, namespace::Root}, transform::to_parsed_lang, - Engines, Namespace, + Engines, Ident, Namespace, }; -use super::{lexical_scope::SymbolMap, root::ResolvedDeclaration, Module, Root}; +///// `contract_id_value` is injected here via forc-pkg when producing the `dependency_namespace` for a contract which has tests enabled. +///// This allows us to provide a contract's `CONTRACT_ID` constant to its own unit tests. +///// +///// This will eventually be refactored out of `sway-core` in favor of creating temporary package dependencies for providing these +///// `CONTRACT_ID`-containing modules: https://github.com/FuelLabs/sway/issues/3077 +//pub fn default_with_contract_id( +// engines: &Engines, +// name: Ident, +// contract_id_value: String, +// experimental: crate::ExperimentalFeatures, +//) -> Result> { +// let handler = <_>::default(); +// default_with_contract_id_inner( +// &handler, +// engines, +// name, +// contract_id_value, +// experimental, +// ) +// .map_err(|_| { +// let (errors, warnings) = handler.consume(); +// assert!(warnings.is_empty()); +// +// // Invariant: `.value == None` => `!errors.is_empty()`. +// vec1::Vec1::try_from_vec(errors).unwrap() +// }) +//} +// +//fn default_with_contract_id_inner( +// handler: &Handler, +// engines: &Engines, +// ns_name: Ident, +// contract_id_value: String, +// experimental: crate::ExperimentalFlags, +//) -> Result { +// // it would be nice to one day maintain a span from the manifest file, but +// // we don't keep that around so we just use the span from the generated const decl instead. +// let mut compiled_constants: SymbolMap = Default::default(); +// // this for loop performs a miniature compilation of each const item in the config +// // FIXME(Centril): Stop parsing. Construct AST directly instead! +// // parser config +// let const_item = format!("pub const CONTRACT_ID: b256 = {contract_id_value};"); +// let const_item_len = const_item.len(); +// let input_arc = std::sync::Arc::from(const_item); +// let token_stream = lex(handler, &input_arc, 0, const_item_len, None).unwrap(); +// let mut parser = Parser::new(handler, &token_stream); +// // perform the parse +// let const_item: ItemConst = parser.parse()?; +// let const_item_span = const_item.span(); +// +// // perform the conversions from parser code to parse tree types +// let name = const_item.name.clone(); +// let attributes = Default::default(); +// // convert to const decl +// let const_decl_id = to_parsed_lang::item_const_to_constant_declaration( +// &mut to_parsed_lang::Context::new(crate::BuildTarget::EVM, experimental), +// handler, +// engines, +// const_item, +// attributes, +// true, +// )?; +// +// // Temporarily disallow non-literals. See https://github.com/FuelLabs/sway/issues/2647. +// let const_decl = engines.pe().get_constant(&const_decl_id); +// let has_literal = match &const_decl.value { +// Some(value) => { +// matches!(value.kind, ExpressionKind::Literal(_)) +// } +// None => false, +// }; +// +// if !has_literal { +// return Err(handler.emit_err(CompileError::ContractIdValueNotALiteral { +// span: const_item_span, +// })); +// } +// +// let ast_node = AstNode { +// content: AstNodeContent::Declaration(Declaration::ConstantDeclaration(const_decl_id)), +// span: const_item_span.clone(), +// }; +// +// let mut ns = Namespace::new(ns_name, None, true); +// +// /// CONTINUE HERE +// +// let mut root = Root::from(Module::new(ns_name.clone(), Visibility::Public, None, vec!())); +// let mut ns = Namespace::init_root(&mut root); +// // This is pretty hacky but that's okay because of this code is being removed pretty soon +// let type_check_ctx = TypeCheckContext::from_namespace(&mut ns, engines, experimental); +// let typed_node = TyAstNode::type_check(handler, type_check_ctx, &ast_node).unwrap(); +// // get the decl out of the typed node: +// // we know as an invariant this must be a const decl, as we hardcoded a const decl in +// // the above `format!`. if it isn't we report an +// // error that only constant items are allowed, defensive programming etc... +// let typed_decl = match typed_node.content { +// TyAstNodeContent::Declaration(decl) => decl, +// _ => { +// return Err( +// handler.emit_err(CompileError::ContractIdConstantNotAConstDecl { +// span: const_item_span, +// }), +// ); +// } +// }; +// compiled_constants.insert(name, ResolvedDeclaration::Typed(typed_decl)); +// +// let mut ret = Module::new(ns_name, visibility, None); +// ret.current_lexical_scope_mut().items.symbols = compiled_constants; +// Ok(ret) +//} -/// `contract_id_value` is injected here via forc-pkg when producing the `dependency_namespace` for a contract which has tests enabled. -/// This allows us to provide a contract's `CONTRACT_ID` constant to its own unit tests. -/// -/// This will eventually be refactored out of `sway-core` in favor of creating temporary package dependencies for providing these -/// `CONTRACT_ID`-containing modules: https://github.com/FuelLabs/sway/issues/3077 -pub fn default_with_contract_id( +/// Factory function for contracts +pub fn namespace_without_contract_id( + package_name: Ident, +) -> Root { + Root::new(package_name, None, false) +} + +/// Factory function for contracts +pub fn namespace_with_contract_id( engines: &Engines, - name: Ident, - visibility: Visibility, + package_name: Ident, contract_id_value: String, experimental: crate::ExperimentalFeatures, -) -> Result> { +) -> Result> { + let root = Root::new(package_name, None, true); let handler = <_>::default(); - default_with_contract_id_inner( - &handler, - engines, - name, - visibility, - contract_id_value, - experimental, - ) - .map_err(|_| { - let (errors, warnings) = handler.consume(); - assert!(warnings.is_empty()); - - // Invariant: `.value == None` => `!errors.is_empty()`. - vec1::Vec1::try_from_vec(errors).unwrap() - }) + bind_contract_id_in_root_module(&handler, engines, contract_id_value, root, experimental) + .map_err(|_| { + let (errors, warnings) = handler.consume(); + assert!(warnings.is_empty()); + + // Invariant: `.value == None` => `!errors.is_empty()`. + vec1::Vec1::try_from_vec(errors).unwrap() + }) } -fn default_with_contract_id_inner( +fn bind_contract_id_in_root_module( handler: &Handler, engines: &Engines, - ns_name: Ident, - visibility: Visibility, contract_id_value: String, + root: Root, experimental: crate::ExperimentalFeatures, -) -> Result { - // it would be nice to one day maintain a span from the manifest file, but - // we don't keep that around so we just use the span from the generated const decl instead. - let mut compiled_constants: SymbolMap = Default::default(); +) -> Result { // this for loop performs a miniature compilation of each const item in the config // FIXME(Centril): Stop parsing. Construct AST directly instead! // parser config - let const_item = format!("pub const CONTRACT_ID: b256 = {contract_id_value};"); + let const_item = format!("pub const {CONTRACT_ID}: b256 = {contract_id_value};"); let const_item_len = const_item.len(); let input_arc = std::sync::Arc::from(const_item); let token_stream = lex(handler, &input_arc, 0, const_item_len, None).unwrap(); @@ -73,7 +175,6 @@ fn default_with_contract_id_inner( let const_item_span = const_item.span(); // perform the conversions from parser code to parse tree types - let name = const_item.name.clone(); let attributes = Default::default(); // convert to const decl let const_decl_id = to_parsed_lang::item_const_to_constant_declaration( @@ -104,32 +205,23 @@ fn default_with_contract_id_inner( content: AstNodeContent::Declaration(Declaration::ConstantDeclaration(const_decl_id)), span: const_item_span.clone(), }; - let mut root = Root::from(Module::new(ns_name.clone(), Visibility::Public, None)); - let mut ns = Namespace::init_root(&mut root); - - let symbol_ctx_ns = Namespace::default(); - let mut symbol_ctx = SymbolCollectionContext::new(symbol_ctx_ns); // This is pretty hacky but that's okay because of this code is being removed pretty soon - let type_check_ctx = - TypeCheckContext::from_namespace(&mut ns, &mut symbol_ctx, engines, experimental); - let typed_node = TyAstNode::type_check(handler, type_check_ctx, &ast_node).unwrap(); - // get the decl out of the typed node: - // we know as an invariant this must be a const decl, as we hardcoded a const decl in - // the above `format!`. if it isn't we report an - // error that only constant items are allowed, defensive programming etc... - let typed_decl = match typed_node.content { - TyAstNodeContent::Declaration(decl) => decl, + // The root object + let mut namespace = Namespace::new(handler, engines, root, false)?; + // TODO: Eliminate this cloning step + let mut symbol_ctx = SymbolCollectionContext::new(namespace.clone()); + let type_check_ctx = TypeCheckContext::from_namespace(&mut namespace, &mut symbol_ctx, engines, experimental); + // Typecheck the const declaration. This will add the binding in the supplied namespace + match TyAstNode::type_check(handler, type_check_ctx, &ast_node).unwrap().content { + TyAstNodeContent::Declaration(_) => Ok(namespace.root()), _ => { - return Err( + // TODO: Should this not be an ICE? If the typecheck fails then it's because our own + // hardcoded declaration is wrong. + Err( handler.emit_err(CompileError::ContractIdConstantNotAConstDecl { span: const_item_span, }), - ); - } - }; - compiled_constants.insert(name, ResolvedDeclaration::Typed(typed_decl)); - - let mut ret = Module::new(ns_name, visibility, None); - ret.current_lexical_scope_mut().items.symbols = compiled_constants; - Ok(ret) + ) + }, + } } diff --git a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs index 62203b13dda..5e5f1605aee 100644 --- a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs +++ b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs @@ -194,6 +194,12 @@ impl Items { } // Symbol not found +// let problem = symbol.as_str() == "codec"; +// if problem { +// dbg!("resolve symbol"); +// dbg!(&symbol); +// panic!(); +// } Err(handler.emit_err(CompileError::SymbolNotFound { name: symbol.clone(), span: symbol.span(), @@ -742,10 +748,13 @@ impl Items { self.symbols .get(name) .cloned() - .ok_or_else(|| CompileError::SymbolNotFound { + .ok_or_else(|| { +// dbg!("check symbol"); +// dbg!(&name); + CompileError::SymbolNotFound { name: name.clone(), span: name.span(), - }) + }}) } pub(crate) fn check_symbols_unique_while_collecting_unifications( @@ -756,10 +765,13 @@ impl Items { .read() .get(&name.into()) .cloned() - .ok_or_else(|| CompileError::SymbolNotFound { + .ok_or_else(|| { +// dbg!("check symbols unique while collecting unifications"); +// dbg!(&name); + CompileError::SymbolNotFound { name: name.clone(), span: name.span(), - }) + }}) } pub(crate) fn clear_symbols_unique_while_collecting_unifications(&self) { diff --git a/sway-core/src/semantic_analysis/namespace/mod.rs b/sway-core/src/semantic_analysis/namespace/mod.rs index 5fba8b2d90e..576b6f8497c 100644 --- a/sway-core/src/semantic_analysis/namespace/mod.rs +++ b/sway-core/src/semantic_analysis/namespace/mod.rs @@ -4,7 +4,6 @@ mod module; #[allow(clippy::module_inception)] mod namespace; mod root; -mod submodule_namespace; mod trait_map; pub use contract_helpers::*; diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 77aa192b3be..40fddacdbee 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -1,8 +1,7 @@ -use crate::{engine_threading::Engines, language::Visibility, Ident}; +use crate::{language::Visibility, Ident}; use super::{ lexical_scope::{Items, LexicalScope}, - root::Root, LexicalScopeId, ModuleName, ModulePath, ModulePathBuf, }; @@ -29,7 +28,7 @@ pub struct Module { /// some library dependency that we include as a submodule. /// /// Note that we *require* this map to produce deterministic codegen results which is why [`FxHasher`] is used. - pub(crate) submodules: im::HashMap>, + submodules: im::HashMap>, /// Keeps all lexical scopes associated with this module. pub lexical_scopes: Vec, /// Current lexical scope id in the lexical scope hierarchy stack. @@ -43,24 +42,24 @@ pub struct Module { visibility: Visibility, /// Empty span at the beginning of the file implementing the module span: Option, - /// Indicates whether the module is external to the current package. External modules are - /// imported in the `Forc.toml` file. - pub is_external: bool, /// An absolute path from the `root` that represents the module location. /// - /// When this is the root module, this is equal to `[]`. When this is a - /// submodule of the root called "foo", this would be equal to `[foo]`. - pub(crate) mod_path: ModulePathBuf, + /// The path of the root module in a package is `[package_name]`. If a module `X` is a submodule + /// of module `Y` which is a submodule of the root module in the package `P`, then the path is + /// `[P, Y, X]`. + mod_path: ModulePathBuf, } -impl Default for Module { - fn default() -> Self { - Self::new(Ident::dummy(), Visibility::Public, None) - } -} +//impl Default for Module { +// fn default() -> Self { +// Self::new(Ident::dummy(), Visibility::Public, None) +// } +//} impl Module { - pub fn new(name: Ident, visibility: Visibility, span: Option) -> Self { + pub(super) fn new(name: Ident, visibility: Visibility, span: Option, parent_mod_path: &ModulePathBuf) -> Self { + let mut mod_path = parent_mod_path.clone(); + mod_path.push(name.clone()); Self { visibility, submodules: Default::default(), @@ -69,29 +68,6 @@ impl Module { current_lexical_scope_id: 0, name, span, - is_external: Default::default(), - mod_path: Default::default(), - } - } - - // Specialized constructor for cloning Namespace::init. Should not be used for anything else - pub(super) fn new_submodule_from_init( - &self, - name: Ident, - visibility: Visibility, - span: Option, - is_external: bool, - mod_path: ModulePathBuf, - ) -> Self { - Self { - visibility, - submodules: self.submodules.clone(), - lexical_scopes: self.lexical_scopes.clone(), - lexical_scopes_spans: self.lexical_scopes_spans.clone(), - current_lexical_scope_id: self.current_lexical_scope_id, - name, - span, - is_external, mod_path, } } @@ -112,6 +88,12 @@ impl Module { self.span = Some(span); } + pub(super) fn add_new_submodule(&mut self, name: &Ident, visibility: Visibility, span: Option) { + let module = Self::new(name.clone(), visibility, span, &self.mod_path); + self.submodules.insert(name.to_string(), module); + } + + pub fn read(&self, _engines: &crate::Engines, mut f: impl FnMut(&Module) -> R) -> R { f(self) } @@ -144,13 +126,8 @@ impl Module { &mut self.submodules } - /// Insert a submodule into this `Module`. - pub fn insert_submodule(&mut self, name: String, submodule: Module) { - self.submodules.insert(name, submodule); - } - /// Lookup the submodule at the given path. - pub fn submodule(&self, _engines: &Engines, path: &ModulePath) -> Option<&Module> { + pub fn submodule(&self, path: &ModulePath) -> Option<&Module> { let mut module = self; for ident in path.iter() { match module.submodules.get(ident.as_str()) { @@ -162,7 +139,7 @@ impl Module { } /// Unique access to the submodule at the given path. - pub fn submodule_mut(&mut self, _engines: &Engines, path: &ModulePath) -> Option<&mut Module> { + pub fn submodule_mut(&mut self, path: &ModulePath) -> Option<&mut Module> { let mut module = self; for ident in path.iter() { match module.submodules.get_mut(ident.as_str()) { @@ -179,25 +156,9 @@ impl Module { pub(crate) fn lookup_submodule( &self, handler: &Handler, - engines: &Engines, path: &[Ident], ) -> Result<&Module, ErrorEmitted> { - match self.submodule(engines, path) { - None => Err(handler.emit_err(module_not_found(path))), - Some(module) => Ok(module), - } - } - - /// Lookup the submodule at the given path. - /// - /// This should be used rather than `Index` when we don't yet know whether the module exists. - pub(crate) fn lookup_submodule_mut( - &mut self, - handler: &Handler, - engines: &Engines, - path: &[Ident], - ) -> Result<&mut Module, ErrorEmitted> { - match self.submodule_mut(engines, path) { + match self.submodule(path) { None => Err(handler.emit_err(module_not_found(path))), Some(module) => Ok(module), } @@ -247,7 +208,6 @@ impl Module { pub fn enter_lexical_scope( &mut self, handler: &Handler, - _engines: &Engines, span: Span, ) -> Result { let id_opt = self.lexical_scopes_spans.get(&span); @@ -287,13 +247,16 @@ impl Module { } } -impl From for Module { - fn from(root: Root) -> Self { - root.module - } -} - -fn module_not_found(path: &[Ident]) -> CompileError { +pub(super) fn module_not_found(path: &[Ident]) -> CompileError { +// let problem = path.len() == 4 +// && path[0].as_str() == "core" +// && path[1].as_str() == "ops" +// && path[2].as_str() == "core" +// && path[3].as_str() == "ops" +// ; +// if problem { +// panic!(); +// } CompileError::ModuleNotFound { span: path.iter().fold(path[0].span(), |acc, this_one| { if acc.source_id() == this_one.span().source_id() { diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 6ed7fe8007b..3f3d353a94a 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -6,89 +6,130 @@ use crate::{ use super::{ module::Module, root::{ResolvedDeclaration, Root}, - submodule_namespace::SubmoduleNamespace, ModulePath, ModulePathBuf, }; use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::span::Span; +use sway_types::{ + constants::{CONTRACT_ID, CORE, PRELUDE, STD}, + span::Span, +}; /// The set of items that represent the namespace context passed throughout type checking. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, /*Default*/)] 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. - /// - /// These include external library dependencies and (when it's added) the `std` prelude. - /// - /// This is passed through type-checking in order to initialise the namespace of each submodule - /// within the project. - init: Module, /// The `root` of the project namespace. /// /// From the root, the entirety of the project's namespace can always be accessed. /// /// The root is initialised from the `init` namespace before type-checking begins. pub(crate) root: Root, - /// An absolute path from the `root` that represents the current module being checked. + /// An absolute path from the `root` that represents the module location. /// - /// E.g. when type-checking the root module, this is equal to `[]`. When type-checking a - /// submodule of the root called "foo", this would be equal to `[foo]`. - pub(crate) mod_path: ModulePathBuf, + /// The path of the root module in a package is `[package_name]`. If a module `X` is a submodule + /// of module `Y` which is a submodule of the root module in the package `P`, then the path is + /// `[P, Y, X]`. + pub(crate) current_mod_path: ModulePathBuf, } impl Namespace { - pub fn new() -> Self { - Self { - init: Module::default(), - mod_path: vec![], - root: Root::default(), + /// Initialize the namespace + /// See also the factory functions in contract_helpers.rs + /// + /// If `import_preludes_into_root` is true then core::prelude and std::prelude will be imported + /// into the root module if core and std are available in the external modules. + pub fn new( + handler: &Handler, + engines: &Engines, + package_root: Root, + import_preludes_into_root: bool, + ) -> Result { + let package_name = package_root.current_package_name().clone(); + let mut res = Self { + root: package_root, + current_mod_path: vec![package_name], + }; + + if import_preludes_into_root { + res.import_implicits(handler, engines)?; } + Ok(res) } - pub fn program_id(&self, engines: &Engines) -> &Module { + // pub fn next_package(&mut self, handler: &Handler, engines: &Engines, next_package_name: Ident, span: Option, contract_id: Option, experimental: ExperimentalFlags) -> Result<(), ErrorEmitted> { + // self.root.next_package(next_package_name, span); + // self.current_mod_path = vec!(self.root.current_package_name().clone()); + // self.is_contract_package = contract_id.is_some(); + // self.import_implicits(&self.current_mod_path.clone()); + // if let Some(id) = contract_id { + // bind_contract_id_in_root_module(handler, engines, id, self, experimental)?; + // } + // Ok(()) + // } + + pub fn root(self) -> Root { + self.root + } + + pub fn current_module(&self) -> &Module { self.root - .module - .submodule(engines, &self.mod_path) + .module_in_current_package(&self.current_mod_path) .unwrap_or_else(|| panic!("Could not retrieve submodule for mod_path.")) } - /// Initialise the namespace at its root from the given initial namespace. - /// If the root module contains submodules these are now considered external. - pub fn init_root(root: &mut Root) -> Self { - assert!( - !root.module.is_external, - "The root module must not be external during compilation" - ); - let mod_path = vec![]; - - // A copy of the root module is used to initialize every new submodule in the program. - // - // Every submodule that has been added before calling init_root is now considered - // external, which we have to enforce at this point. - fn set_submodules_external(module: &mut Module) { - for (_, submod) in module.submodules_mut().iter_mut() { - if !submod.is_external { - submod.is_external = true; - set_submodules_external(submod); - } - } - } + pub fn current_module_mut(&mut self) -> &mut Module { +// dbg!(&self.current_mod_path); + self.root + .module_mut_in_current_package(&self.current_mod_path) + .unwrap_or_else(|| panic!("Could not retrieve submodule for mod_path.")) + } - set_submodules_external(&mut root.module); - // The init module itself is not external - root.module.is_external = false; + pub(crate) fn current_module_has_submodule(&self, submod_name: &Ident) -> bool { + self.current_module() + .submodule(&[submod_name.clone()]) + .is_some() + } - Self { - init: root.module.clone(), - root: root.clone(), - mod_path, - } + pub fn current_package_name(&self) -> &Ident { + self.root.current_package_name() } + // /// Initialise the namespace at its root from the given initial namespace. + // /// If the root module contains submodules these are now considered external. + // pub fn init_root(root: &mut Root) -> Self { + // assert!( + // !root.module.is_external, + // "The root module must not be external during compilation" + // ); + // let mod_path = vec![]; + // + // // A copy of the root module is used to initialize every new submodule in the program. + // // + // // Every submodule that has been added before calling init_root is now considered + // // external, which we have to enforce at this point. + // fn set_submodules_external(module: &mut Module) { + // for (_, submod) in module.submodules_mut().iter_mut() { + // if !submod.is_external { + // submod.is_external = true; + // set_submodules_external(submod); + // } + // } + // } + // + // set_submodules_external(&mut root.module); + // // The init module itself is not external + // root.module.is_external = false; + // + // Self { + // init: root.module.clone(), + // root: root.clone(), + // mod_path, + // } + // } + /// A reference to the path of the module currently being processed. - pub fn mod_path(&self) -> &ModulePath { - &self.mod_path + pub fn current_mod_path(&self) -> &ModulePathBuf { + &self.current_mod_path } /// Prepends the module path into the prefixes. @@ -96,41 +137,52 @@ impl Namespace { &'a self, prefixes: impl IntoIterator, ) -> ModulePathBuf { - self.mod_path.iter().chain(prefixes).cloned().collect() - } - - /// A reference to the root of the project namespace. - pub fn root(&self) -> &Root { - &self.root + self.current_mod_path + .iter() + .chain(prefixes) + .cloned() + .collect() } - pub fn root_module(&self) -> &Module { - &self.root.module + /// Convert a parsed path to a full path. + pub fn parsed_path_to_full_path(&self, parsed_path: &ModulePathBuf, is_relative_to_package_root: bool) -> ModulePathBuf { + if is_relative_to_package_root { + // Path is relative to the root module in the current package. Prepend the package name + let mut path = vec!(self.current_package_name().clone()); + for ident in parsed_path.iter() { + path.push(ident.clone()) + } + path + } else if self.current_module_has_submodule(&parsed_path[0]) { + // A submodule exists matching the first identifier in the parsed path. + // The path is therefore assumed to be relative to the current module, so prepend the current module path. + self.prepend_module_path(parsed_path) + } else { + // The path refers to an external module, so the path is already a full path. + parsed_path.to_vec() + } } + + // /// A reference to the root of the project namespace. + // pub fn root(&self) -> &Root { + // &self.root + // } - /// Access to the current [Module], i.e. the module at the inner `mod_path`. - pub fn module(&self, engines: &Engines) -> &Module { - self.root - .module - .lookup_submodule(&Handler::default(), engines, &self.mod_path) - .unwrap() + pub fn current_package_root_module(&self) -> &Module { + &self.root.current_package_root_module() } - /// Mutable access to the current [Module], i.e. the module at the inner `mod_path`. - pub fn module_mut(&mut self, engines: &Engines) -> &mut Module { - self.root - .module - .lookup_submodule_mut(&Handler::default(), engines, &self.mod_path) - .unwrap() + pub fn module_from_absolute_path(&self, path: &ModulePathBuf) -> Option<&Module> { + self.root.module_from_absolute_path(path) } - pub fn lookup_submodule_from_absolute_path( + // Like module_from_absolute_path, but throws an error if the module is not found + pub fn require_module_from_absolute_path( &self, handler: &Handler, - engines: &Engines, - path: &ModulePath, + path: &ModulePathBuf, ) -> Result<&Module, ErrorEmitted> { - self.root.module.lookup_submodule(handler, engines, path) + self.root.require_module(handler, path) } /// Returns true if the current module being checked is a direct or indirect submodule of @@ -146,31 +198,16 @@ impl Namespace { /// the `true_if_same` is returned. pub(crate) fn module_is_submodule_of( &self, - _engines: &Engines, absolute_module_path: &ModulePath, true_if_same: bool, ) -> bool { - // `mod_path` does not contain the root name, so we have to separately check - // that the root name is equal to the module package name. - let root_name = self.root.module.name(); - - let (package_name, modules) = absolute_module_path.split_first().expect("Absolute module path must have at least one element, because it always contains the package name."); - - if root_name != package_name { - return false; - } - - if self.mod_path.len() < modules.len() { - return false; - } - - let is_submodule = modules + let is_submodule = absolute_module_path .iter() - .zip(self.mod_path.iter()) + .zip(self.current_mod_path.iter()) .all(|(left, right)| left == right); if is_submodule { - if self.mod_path.len() == modules.len() { + if self.current_mod_path.len() == absolute_module_path.len() { true_if_same } else { true @@ -183,12 +220,20 @@ impl Namespace { /// Returns true if the module given by the `absolute_module_path` is external /// to the current package. External modules are imported in the `Forc.toml` file. pub(crate) fn module_is_external(&self, absolute_module_path: &ModulePath) -> bool { - let root_name = self.root.module.name(); - assert!(!absolute_module_path.is_empty(), "Absolute module path must have at least one element, because it always contains the package name."); - root_name != &absolute_module_path[0] + self.root.current_package_name() != &absolute_module_path[0] } + + pub fn package_exists(&self, name: &Ident) -> bool { + self.module_from_absolute_path(&vec![name.clone()]).is_some() + } + + pub(crate) fn current_module_has_binding(&self, engines: &Engines, symbol: &Ident) -> bool { + let dummy_handler = Handler::default(); + self.root.item_lookup(&dummy_handler, engines, symbol, &self.current_mod_path, &self.current_mod_path, true).is_ok() + } + /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. pub(crate) fn resolve_symbol( &self, @@ -196,9 +241,21 @@ impl Namespace { engines: &Engines, symbol: &Ident, self_type: Option, + ) -> Result { + self.resolve_symbol_with_path(handler, engines, &self.current_mod_path, symbol, self_type) + } + + /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. + pub(crate) fn resolve_symbol_with_path( + &self, + handler: &Handler, + engines: &Engines, + mod_path: &ModulePathBuf, + symbol: &Ident, + self_type: Option, ) -> Result { self.root - .resolve_symbol(handler, engines, &self.mod_path, symbol, self_type) + .resolve_symbol(handler, engines, mod_path, symbol, self_type) } /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. @@ -233,65 +290,289 @@ impl Namespace { call_path: &CallPath, self_type: Option, ) -> Result { - self.root - .resolve_call_path(handler, engines, &self.mod_path, call_path, self_type) + let full_path = call_path.to_fullpath(engines, &self); +// let problem = +// call_path.suffix.as_str() == "Some" +// && self.current_mod_path.len() == 2 +// && self.current_mod_path[0].as_str() == "std" +// && self.current_mod_path[1].as_str() == "vec"; +// if problem { +// dbg!(call_path); +// dbg!(&full_path); +// }; + self.root.resolve_call_path( + handler, + engines, + &self.current_mod_path, + &full_path, + self_type, + ) + } + +// /// Short-hand for calling [Root::resolve_call_and_root_type_id] on `root` with the `mod_path`. +// pub fn resolve_call_path_and_root_type_id( +// &self, +// handler: &Handler, +// engines: &Engines, +// root_type_id: TypeId, +// as_trait: Option, +// call_path: &CallPath, +// self_type: Option, +// ) -> Result { +// self.root.resolve_call_path_and_root_type_id(handler, engines, self.current_module(), root_type_id, as_trait, call_path, self_type).map(|decl| decl.expect_typed()) +// } + + // Import core::prelude::*, std::prelude::* and ::CONTRACT_ID as appropriate into the current module + fn import_implicits( + &mut self, + handler: &Handler, + engines: &Engines, + ) -> Result<(), ErrorEmitted> { + // Import preludes + let package_name = self.current_package_name().to_string(); + let core_string = CORE.to_string(); + let core_ident = Ident::new_no_span(core_string.clone()); + let prelude_ident = Ident::new_no_span(PRELUDE.to_string()); + if package_name == CORE { + // Do nothing + } else if package_name == STD { + // Import core::prelude::* + assert!(self.root.exists_as_external(&core_string)); + self.root.star_import( + handler, + engines, + &[core_ident, prelude_ident], + &self.current_mod_path, + Visibility::Private, + )? + } else { + // Import core::prelude::* and std::prelude::* + if self.root.exists_as_external(&core_string) { + self.root.star_import( + handler, + engines, + &[core_ident, prelude_ident.clone()], + &self.current_mod_path, + Visibility::Private, + )?; + } + + let std_string = STD.to_string(); + // Only import std::prelude::* if std exists as a dependency + if self.root.exists_as_external(&std_string) { + self.root.star_import( + handler, + engines, + &[Ident::new_no_span(std_string), prelude_ident], + &self.current_mod_path, + Visibility::Private, + )? + } + } + + // Import contract id. CONTRACT_ID is declared in the root module, so only import it into non-root modules + if self.root.is_contract_package() && self.current_mod_path.len() > 1 { + // import ::CONTRACT_ID + self.root.item_import( + handler, + engines, + &[Ident::new_no_span(package_name)], + &Ident::new_no_span(CONTRACT_ID.to_string()), + &self.current_mod_path, + None, + Visibility::Private, + )? + } + + Ok(()) } - /// "Enter" the submodule at the given path by returning a new [SubmoduleNamespace]. - /// - /// Here we temporarily change `mod_path` to the given `dep_mod_path` and wrap `self` in a - /// [SubmoduleNamespace] type. When dropped, the [SubmoduleNamespace] resets the `mod_path` - /// back to the original path so that we can continue type-checking the current module after - /// finishing with the dependency. pub(crate) fn enter_submodule( &mut self, + handler: &Handler, engines: &Engines, mod_name: Ident, visibility: Visibility, module_span: Span, - ) -> SubmoduleNamespace { - let init = self.init.clone(); - let is_external = self.module(engines).is_external; - let submod_path: Vec<_> = self - .mod_path - .iter() - .cloned() - .chain(Some(mod_name.clone())) - .collect(); - self.module_mut(engines) - .submodules - .entry(mod_name.to_string()) - .or_insert(init.new_submodule_from_init( - mod_name, - visibility, - Some(module_span), - is_external, - submod_path.clone(), - )); - let parent_mod_path = std::mem::replace(&mut self.mod_path, submod_path.clone()); - SubmoduleNamespace { - namespace: self, - parent_mod_path, + ) -> Result<(), ErrorEmitted> { +// println!( +// "Current module is {:?}. Entering submodule {:?}.", +// self.current_mod_path, mod_name +// ); + let mut import_implicits = false; + + // Ensure the new module exists and is initialized properly + if !self + .current_module() + .submodules() + .contains_key(&mod_name.to_string()) + { + // Entering a new module. Add a new one. + self.current_module_mut() + .add_new_submodule(&mod_name, visibility, Some(module_span)); + import_implicits = true; } + + // Update self to point to the new module + self.current_mod_path.push(mod_name.clone()); + + // Import implicits into the newly created module. + if import_implicits { + self.import_implicits(handler, engines)?; + } + +// println!("New mod path is {:?}.", self.current_mod_path); + + Ok(()) } + // /// "Enter" the submodule at the given path by returning a new [SubmoduleNamespace]. + // /// + // /// Here we temporarily change `mod_path` to the given `dep_mod_path` and wrap `self` in a + // /// [SubmoduleNamespace] type. When dropped, the [SubmoduleNamespace] resets the `mod_path` + // /// back to the original path so that we can continue type-checking the current module after + // /// finishing with the dependency. + // pub(crate) fn enter_submodule( + // &mut self, + // engines: &Engines, + // mod_name: Ident, + // visibility: Visibility, + // module_span: Span, + // ) -> SubmoduleNamespace { + // let init = self.init.clone(); + // let is_external = self.module(engines).is_external; + // let submod_path: Vec<_> = self + // .mod_path + // .iter() + // .cloned() + // .chain(Some(mod_name.clone())) + // .collect(); + // self.module_mut(engines) + // .submodules + // .entry(mod_name.to_string()) + // .or_insert(init.new_submodule_from_init( + // mod_name, + // visibility, + // Some(module_span), + // is_external, + // submod_path.clone(), + // )); + // let parent_mod_path = std::mem::replace(&mut self.current_mod_path, submod_path.clone()); + // SubmoduleNamespace { + // namespace: self, + // parent_mod_path, + // } + // } + /// Pushes a new submodule to the namespace's module hierarchy. pub fn push_submodule( &mut self, + handler: &Handler, engines: &Engines, mod_name: Ident, visibility: Visibility, module_span: Span, - ) { - self.module_mut(engines) - .submodules - .entry(mod_name.to_string()) - .or_insert(Module::new(mod_name.clone(), visibility, Some(module_span))); - self.mod_path.push(mod_name); + ) -> Result<(), ErrorEmitted> { +// println!("Pushing module {:?}.", mod_name); + match self.enter_submodule(handler, engines, mod_name, visibility, module_span) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } } /// Pops the current submodule from the namespace's module hierarchy. pub fn pop_submodule(&mut self) { - self.mod_path.pop(); +// println!("Popping: Leaving module {:?}.", self.current_mod_path); + self.current_mod_path.pop(); +// println!("New module path is {:?}.", self.current_mod_path); + } + + pub(crate) fn star_import_to_current_module( + &mut self, + handler: &Handler, + engines: &Engines, + src: &ModulePath, + visibility: Visibility, + ) -> Result<(), ErrorEmitted> { + self.root + .star_import(handler, engines, src, &self.current_mod_path, visibility) + } + + pub(crate) fn variant_star_import_to_current_module( + &mut self, + handler: &Handler, + engines: &Engines, + src: &ModulePath, + enum_name: &Ident, + visibility: Visibility, + ) -> Result<(), ErrorEmitted> { + self.root.variant_star_import( + handler, + engines, + src, + &self.current_mod_path, + enum_name, + visibility, + ) + } + + pub(crate) fn self_import_to_current_module( + &mut self, + handler: &Handler, + engines: &Engines, + src: &ModulePath, + alias: Option, + visibility: Visibility, + ) -> Result<(), ErrorEmitted> { + self.root.self_import( + handler, + engines, + src, + &self.current_mod_path, + alias, + visibility, + ) + } + + pub(crate) fn item_import_to_current_module( + &mut self, + handler: &Handler, + engines: &Engines, + src: &ModulePath, + item: &Ident, + alias: Option, + visibility: Visibility, + ) -> Result<(), ErrorEmitted> { + self.root.item_import( + handler, + engines, + src, + item, + &self.current_mod_path, + alias, + visibility, + ) + } + + pub(crate) fn variant_import_to_current_module( + &mut self, + handler: &Handler, + engines: &Engines, + src: &ModulePath, + enum_name: &Ident, + variant_name: &Ident, + alias: Option, + visibility: Visibility, + ) -> Result<(), ErrorEmitted> { + self.root.variant_import( + handler, + engines, + src, + enum_name, + variant_name, + &self.current_mod_path, + alias, + visibility, + ) } } diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 7d4e22b7265..a0f071a1228 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -1,13 +1,15 @@ use std::fmt; -use super::{module::Module, trait_map::TraitMap, Ident}; +use super::{ + module::Module, trait_map::TraitMap, Ident, ModuleName, +}; use crate::{ decl_engine::{DeclEngine, DeclRef}, engine_threading::*, language::{ parsed::*, - ty::{self, StructDecl, TyDecl}, - CallPath, Visibility, + ty::{self, StructDecl, TyDecl, }, + CallPath, CallPathType, Visibility, }, namespace::{ModulePath, ModulePathBuf}, semantic_analysis::type_resolve::{resolve_associated_item, resolve_associated_type}, @@ -17,8 +19,10 @@ use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; -use sway_types::Spanned; +use sway_types::{span::Span, Spanned}; use sway_utils::iter_prefixes; +use rustc_hash::FxHasher; +use std::hash::BuildHasherDefault; #[derive(Clone, Debug)] pub enum ResolvedDeclaration { @@ -150,7 +154,7 @@ impl ResolvedDeclaration { } } -/// The root module, from which all other modules can be accessed. +/// The root module, from which all other module dependencies can be accessed. /// /// This is equivalent to the "crate root" of a Rust crate. /// @@ -158,12 +162,148 @@ impl ResolvedDeclaration { /// 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, Default)] +#[derive(Clone, Debug, /*Default*/)] pub struct Root { - pub(crate) module: Module, + // The contents of the package being compiled. + current_package: Module, + // True if the current package is a contract, false otherwise. + is_contract_package: bool, + // The external dependencies of the current package. Note that an external package is + // represented as a `Root` object. This is because external packages may have their own external + // dependencies which are needed for lookups, but which are not directly accessible to the + // current package. + external_packages: im::HashMap>, } impl Root { + + // Create a new root object with a root module in the current package. + // + // To ensure the correct initialization the factory functions `package_root_without_contract_id` + // and `package_root_with_contract_id` are supplied in `contract_helpers`. + // + // External packages must be added afterwards by calling `add_external` + pub(super) fn new(package_name: Ident, span: Option, is_contract_package: bool) -> Self { + // The root module must be public + let module = Module::new(package_name, Visibility::Public, span, &vec!()); + Self { + current_package: module, + is_contract_package, + external_packages: Default::default(), + } + } + + // Add an external package to this package. The package name must be supplied, since the package + // may be referred to by a different name in the forc.toml file than the actual name of the + // package. + pub fn add_external(&mut self, package_name: String, external_package: Root) { + assert!(!self.external_packages.contains_key(&package_name)); + self.external_packages.insert(package_name, external_package); + } + + pub(super) fn exists_as_external(&self, package_name: &String) -> bool { + self.external_packages.contains_key(package_name) + } + +// pub(super) fn next_package(&mut self, next_package_name: Ident, span: Option) { +// // TODO: reject if the new package name already exist +// let new_package = Module::new(next_package_name, Visibility::Public, span, &vec!()); +// let old_package = std::mem::replace(&mut self.current_package, new_package); +// self.external_packages.insert(old_package.name().to_string(), old_package); +// } + + pub(super) fn current_package_root_module(&self) -> &Module { + &self.current_package + } + + pub(super) fn current_package_name(&self) -> &Ident { + self.current_package.name() + } + + fn check_path_is_in_current_package(&self, mod_path: &ModulePathBuf) -> bool { + !mod_path.is_empty() && mod_path[0] == *self.current_package.name() + } + + fn package_relative_path(mod_path: &ModulePathBuf) -> ModulePathBuf { + mod_path[1..].to_vec() + } + + pub(super) fn is_contract_package(&self) -> bool { + self.is_contract_package + } + + pub fn add_span_to_root_module(&mut self, span: Span) { + self.current_package.set_span(span) + } + + // Find module in the current environment. `mod_path` must be a fully qualified path + pub(super) fn module_from_absolute_path(&self, mod_path: &ModulePathBuf) -> Option<&Module> { + assert!(!mod_path.is_empty()); + let package_relative_path = Self::package_relative_path(mod_path); + if mod_path[0] == *self.current_package.name() { + self.current_package.submodule(&package_relative_path) + } else if let Some(external_package) = self.external_packages.get(&mod_path[0].to_string()) { + external_package.current_package_root_module().submodule(&package_relative_path) + } else { + None + } + } + + // Find module in the current environment. `mod_path` must be a fully qualified path. + // Throw an error if the module doesn't exist + pub(super) fn require_module(&self, handler: &Handler, mod_path: &ModulePathBuf) -> Result<&Module, ErrorEmitted> { + match self.module_from_absolute_path(mod_path) { + Some(module) => Ok(module), + None => Err(handler.emit_err(crate::namespace::module::module_not_found(mod_path))), + } + } + + // Find a module in the current package. `mod_path` must be a fully qualified path + pub(super) fn module_in_current_package(&self, mod_path: &ModulePathBuf) -> Option<&Module> { +// dbg!(mod_path); +// dbg!(self.current_package_name()); + assert!(self.check_path_is_in_current_package(mod_path)); + self.module_from_absolute_path(mod_path) + } + + // Find mutable module in the current environment. `mod_path` must be a fully qualified path + pub(super) fn module_mut_from_absolute_path(&mut self, mod_path: &ModulePathBuf) -> Option<&mut Module> { + assert!(!mod_path.is_empty()); + let package_relative_path = Self::package_relative_path(mod_path); + if *self.current_package.name() == mod_path[0] { + self.current_package.submodule_mut(&package_relative_path) + } else if let Some(external_package) = self.external_packages.get_mut(&mod_path[0].to_string()) { + external_package.module_mut_in_current_package(&package_relative_path) + } else { + None + } + } + + // Find mutable module in the current environment. `mod_path` must be a fully qualified path. + // Throw an error if the module doesn't exist + pub(super) fn require_module_mut(&mut self, handler: &Handler, mod_path: &ModulePathBuf) -> Result<&mut Module, ErrorEmitted> { + match self.module_mut_from_absolute_path(mod_path) { + Some(module) => Ok(module), + None => Err(handler.emit_err(crate::namespace::module::module_not_found(mod_path))), + } + } + + // Find a mutable module in the current package. `mod_path` must be a fully qualified path + pub(super) fn module_mut_in_current_package(&mut self, mod_path: &ModulePathBuf) -> Option<&mut Module> { +// dbg!(mod_path); + assert!(self.check_path_is_in_current_package(mod_path)); + self.module_mut_from_absolute_path(mod_path) + } + + // Find a mutable module in the current package. `mod_path` must be a fully qualified path + // Throw an error if the module doesn't exist + pub(super) fn require_module_mut_in_current_package(&mut self, handler: &Handler, mod_path: &ModulePathBuf) -> Result<&mut Module, ErrorEmitted> { + assert!(self.check_path_is_in_current_package(mod_path)); + self.require_module_mut(handler, mod_path) + } + + + ////// IMPORT ////// /// Given a path to a `src` module, create synonyms to every symbol in that module to the given @@ -180,28 +320,12 @@ impl Root { dst: &ModulePath, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - self.check_module_privacy(handler, engines, src, dst)?; + self.check_module_privacy(handler, src, dst)?; - let src_mod = self.module.lookup_submodule(handler, engines, src)?; + let src_mod = self.require_module(handler, &src.to_vec())?; let mut decls_and_item_imports = vec![]; - let get_path = |mod_path: Vec| { - let mut is_external = false; - if let Some(submodule) = src_mod.submodule(engines, &[mod_path[0].clone()]) { - is_external = submodule.is_external - }; - - let mut path = src[..1].to_vec(); - if is_external { - path = mod_path; - } else { - path.extend(mod_path); - } - - path - }; - // Collect all items declared in the source module for (symbol, decl) in src_mod.current_items().symbols.iter() { if is_ancestor(src, dst) || decl.visibility(engines).is_public() { @@ -214,7 +338,7 @@ impl Root { src_mod.current_items().use_item_synonyms.iter() { if src_visibility.is_public() { - decls_and_item_imports.push((symbol.clone(), decl.clone(), get_path(path.clone()))) + decls_and_item_imports.push((symbol.clone(), decl.clone(), path.clone())) } } @@ -230,14 +354,14 @@ impl Root { { for (path, decl, src_visibility) in bindings.iter() { if src_visibility.is_public() { - glob_imports.push((symbol.clone(), decl.clone(), get_path(path.clone()))) + glob_imports.push((symbol.clone(), decl.clone(), path.clone())) } } } } let implemented_traits = src_mod.current_items().implemented_traits.clone(); - let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?; + let dst_mod = self.require_module_mut_in_current_package(handler, &dst.to_vec())?; dst_mod .current_items_mut() .implemented_traits @@ -276,15 +400,16 @@ impl Root { self.item_import(handler, engines, src, last_item, dst, alias, visibility) } - fn item_lookup( + pub(super) fn item_lookup( &self, handler: &Handler, engines: &Engines, item: &Ident, src: &ModulePath, dst: &ModulePath, + ignore_visibility: bool, ) -> Result<(ResolvedDeclaration, ModulePathBuf), ErrorEmitted> { - let src_mod = self.module.lookup_submodule(handler, engines, src)?; + let src_mod = self.require_module(handler, &src.to_vec())?; let src_items = src_mod.current_items(); let (decl, path, src_visibility) = if let Some(decl) = src_items.symbols.get(item) { @@ -327,13 +452,15 @@ impl Root { } } else { // Symbol not found +// dbg!("item lookup"); +// dbg!(&item); return Err(handler.emit_err(CompileError::SymbolNotFound { name: item.clone(), span: item.span(), })); }; - if !src_visibility.is_public() { + if !ignore_visibility && !src_visibility.is_public() { handler.emit_err(CompileError::ImportPrivateSymbol { name: item.clone(), span: item.span(), @@ -357,10 +484,10 @@ impl Root { alias: Option, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - self.check_module_privacy(handler, engines, src, dst)?; - let src_mod = self.module.lookup_submodule(handler, engines, src)?; + self.check_module_privacy(handler, src, dst)?; + let src_mod = self.require_module(handler, &src.to_vec())?; - let (decl, path) = self.item_lookup(handler, engines, item, src, dst)?; + let (decl, path) = self.item_lookup(handler, engines, item, src, dst, false)?; let mut impls_to_insert = TraitMap::default(); if decl.is_typed() { @@ -398,7 +525,7 @@ impl Root { } // no matter what, import it this way though. - let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?; + let dst_mod = self.require_module_mut_in_current_package(handler, &dst.to_vec())?; let check_name_clash = |name| { if dst_mod.current_items().use_item_synonyms.contains_key(name) { handler.emit_err(CompileError::ShadowsOtherSymbol { name: name.into() }); @@ -444,13 +571,14 @@ impl Root { alias: Option, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - self.check_module_privacy(handler, engines, src, dst)?; + self.check_module_privacy(handler, src, dst)?; let decl_engine = engines.de(); let parsed_decl_engine = engines.pe(); - let (decl, path) = self.item_lookup(handler, engines, enum_name, src, dst)?; - + let (decl, /*mut*/ path) = self.item_lookup(handler, engines, enum_name, src, dst, false)?; + //path.push(enum_name.clone()); + match decl { ResolvedDeclaration::Parsed(decl) => { if let Declaration::EnumDeclaration(decl_id) = decl { @@ -460,7 +588,7 @@ impl Root { enum_decl.variants.iter().find(|v| v.name == *variant_name) { // import it this way. - let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?; + let dst_mod = self.require_module_mut_in_current_package(handler, &dst.to_vec())?; let check_name_clash = |name| { if dst_mod.current_items().use_item_synonyms.contains_key(name) { handler.emit_err(CompileError::ShadowsOtherSymbol { @@ -512,6 +640,8 @@ impl Root { } }; } else { +// dbg!("variant import parsed"); +// dbg!(&variant_name); return Err(handler.emit_err(CompileError::SymbolNotFound { name: variant_name.clone(), span: variant_name.span(), @@ -532,7 +662,7 @@ impl Root { enum_decl.variants.iter().find(|v| v.name == *variant_name) { // import it this way. - let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?; + let dst_mod = self.require_module_mut_in_current_package(handler, &dst.to_vec())?; let check_name_clash = |name| { if dst_mod.current_items().use_item_synonyms.contains_key(name) { handler.emit_err(CompileError::ShadowsOtherSymbol { @@ -580,7 +710,9 @@ impl Root { } }; } else { - return Err(handler.emit_err(CompileError::SymbolNotFound { +// dbg!("variant import typed"); +// dbg!(&variant_name); + return Err(handler.emit_err(CompileError::SymbolNotFound { name: variant_name.clone(), span: variant_name.span(), })); @@ -609,12 +741,13 @@ impl Root { enum_name: &Ident, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - self.check_module_privacy(handler, engines, src, dst)?; + self.check_module_privacy(handler, src, dst)?; let parsed_decl_engine = engines.pe(); let decl_engine = engines.de(); - let (decl, path) = self.item_lookup(handler, engines, enum_name, src, dst)?; + let (decl, /*mut*/ path) = self.item_lookup(handler, engines, enum_name, src, dst, false)?; +// path.push(enum_name.clone()); match decl { ResolvedDeclaration::Parsed(Declaration::EnumDeclaration(decl_id)) => { @@ -630,8 +763,7 @@ impl Root { }); // import it this way. - self.module - .lookup_submodule_mut(handler, engines, dst)? + self.require_module_mut_in_current_package(handler, &dst.to_vec())? .current_items_mut() .insert_glob_use_symbol( engines, @@ -660,8 +792,7 @@ impl Root { })); // import it this way. - self.module - .lookup_submodule_mut(handler, engines, dst)? + self.require_module_mut_in_current_package(handler, &dst.to_vec())? .current_items_mut() .insert_glob_use_symbol( engines, @@ -686,24 +817,37 @@ impl Root { fn check_module_privacy( &self, handler: &Handler, - engines: &Engines, src: &ModulePath, dst: &ModulePath, ) -> Result<(), ErrorEmitted> { - // you are always allowed to access your ancestor's symbols - if !is_ancestor(src, dst) { - // we don't check the first prefix because direct children are always accessible - for prefix in iter_prefixes(src).skip(1) { - let module = self.module.lookup_submodule(handler, engines, prefix)?; - if module.visibility().is_private() { - let prefix_last = prefix[prefix.len() - 1].clone(); - handler.emit_err(CompileError::ImportPrivateModule { - span: prefix_last.span(), - name: prefix_last, - }); - } - } - } + let mut ignored_prefixes = 0; + + // Ignore visibility of common ancestor modules + for (src_prefix, dst_prefix) in src.iter().zip(dst) { + if src_prefix != dst_prefix { + break; + } + ignored_prefixes += 1; + } + + // Ignore visibility of direct submodules of the destination module + if dst.len() == ignored_prefixes { + ignored_prefixes += 1; + } + + // Check visibility of remaining submodules in the source path + for prefix in iter_prefixes(src).skip(ignored_prefixes) { + let module = self.require_module(handler, &prefix.to_vec())?; + if module.visibility().is_private() { + let prefix_last = prefix[prefix.len() - 1].clone(); + handler.emit_err(CompileError::ImportPrivateModule { + span: prefix_last.span(), + name: prefix_last, + }); + } + } + +// } Ok(()) } @@ -726,23 +870,35 @@ impl Root { Ok(decl) } + // TODO: Move this into root, and separate into two: Check if call_path can be resolved in the local scope, otherwise check if it can be resolved as an absolute path. + // TODO: Move type_check_context::resolve_call_path_with_visibility_check_and_modpath to here, to avoid external mod_paths to be decontextualized. pub(crate) fn resolve_call_path_and_mod_path( &self, handler: &Handler, engines: &Engines, - mod_path: &ModulePath, + _mod_path: &ModulePath, call_path: &CallPath, self_type: Option, ) -> Result<(ResolvedDeclaration, ModulePathBuf), ErrorEmitted> { - let symbol_path: Vec<_> = mod_path - .iter() - .chain(&call_path.prefixes) - .cloned() - .collect(); +// if call_path.prefixes.len() > 1 && call_path.prefixes[0].as_str() == "core" && call_path.prefixes[1].as_str() == "core" { +// panic!(); +// } +// let problem = call_path.suffix.as_str() == "AbiEncode"; +// if problem { +// dbg!(call_path); +// dbg!(mod_path); +// }; +// let symbol_path: Vec<_> = mod_path +// .iter() +// .chain(&call_path.prefixes) +// .cloned() + // .collect(); + assert!(matches!(call_path.callpath_type, CallPathType::Full)); self.resolve_symbol_and_mod_path( handler, engines, - &symbol_path, + //&symbol_path, + &call_path.prefixes, &call_path.suffix, self_type, ) @@ -766,6 +922,8 @@ impl Root { Ok(decl) } + // Resolve a path. The first identifier in the path is the package name, which may be the + // current package or an external one. fn resolve_symbol_and_mod_path( &self, handler: &Handler, @@ -774,17 +932,49 @@ impl Root { symbol: &Ident, self_type: Option, ) -> Result<(ResolvedDeclaration, Vec), ErrorEmitted> { + assert!(!mod_path.is_empty()); + if mod_path[0] == *self.current_package_name() { + self.resolve_symbol_and_mod_path_inner(handler, engines, mod_path, symbol, self_type) + } else { + match self.external_packages.get(mod_path[0].as_str()) { + Some(ext_root) => { + // The path must be resolved in an external package. + // The root module in that package may have a different name than the name we + // use to refer to the package, so replace it. + let mut new_mod_path = vec!(ext_root.current_package_name().clone()); + for id in mod_path.iter().skip(1) { + new_mod_path.push(id.clone()); + } + ext_root.resolve_symbol_and_mod_path_inner(handler, engines, &new_mod_path, symbol, self_type) + }, + None => Err(handler.emit_err(crate::namespace::module::module_not_found(mod_path))) + } + } + } + + // Resolve a path within the current package. External packages are not considered. The path + // must still contain the package name as its first identifier. + fn resolve_symbol_and_mod_path_inner( + &self, + handler: &Handler, + engines: &Engines, + mod_path: &ModulePath, + symbol: &Ident, + self_type: Option, + ) -> Result<(ResolvedDeclaration, Vec), ErrorEmitted> { + assert!(!mod_path.is_empty()); + assert!(mod_path[0] == *self.current_package_name()); // This block tries to resolve associated types - let mut module = &self.module; - let mut current_mod_path = vec![]; + let mut module = &self.current_package; + let mut current_mod_path = vec![mod_path[0].clone()]; let mut decl_opt = None; - for ident in mod_path.iter() { + for ident in mod_path.iter().skip(1) { if let Some(decl) = decl_opt { decl_opt = Some(resolve_associated_type( handler, engines, module, ident, decl, None, self_type, )?); } else { - match module.submodules.get(ident.as_str()) { + match module.submodule(&[ident.clone()]) { Some(ns) => { module = ns; current_mod_path.push(ident.clone()); @@ -806,8 +996,7 @@ impl Root { return Ok((decl, current_mod_path)); } - self.module - .lookup_submodule(handler, engines, mod_path) + self.require_module(handler, &mod_path.to_vec()) .and_then(|module| { let decl = module .current_lexical_scope() @@ -818,12 +1007,6 @@ impl Root { } } -impl From for Root { - fn from(module: Module) -> Self { - Root { module } - } -} - fn is_ancestor(src: &ModulePath, dst: &ModulePath) -> bool { dst.len() >= src.len() && src.iter().zip(dst).all(|(src, dst)| src == dst) } diff --git a/sway-core/src/semantic_analysis/namespace/submodule_namespace.rs b/sway-core/src/semantic_analysis/namespace/submodule_namespace.rs deleted file mode 100644 index e63b9e76806..00000000000 --- a/sway-core/src/semantic_analysis/namespace/submodule_namespace.rs +++ /dev/null @@ -1,35 +0,0 @@ -use super::{namespace::Namespace, ModulePathBuf}; - -/// A namespace session type representing the type-checking of a submodule. -/// -/// This type allows for re-using the parent's `Namespace` in order to provide access to the -/// `root` and `init` throughout type-checking of the submodule, but with an updated `mod_path` to -/// represent the submodule's path. When dropped, the `SubmoduleNamespace` reset's the -/// `Namespace`'s `mod_path` to the parent module path so that type-checking of the parent may -/// continue. -pub struct SubmoduleNamespace<'a> { - pub(crate) namespace: &'a mut Namespace, - pub(crate) parent_mod_path: ModulePathBuf, -} - -impl<'a> std::ops::Deref for SubmoduleNamespace<'a> { - type Target = Namespace; - fn deref(&self) -> &Self::Target { - self.namespace - } -} - -impl<'a> std::ops::DerefMut for SubmoduleNamespace<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.namespace - } -} - -impl<'a> Drop for SubmoduleNamespace<'a> { - fn drop(&mut self) { - // Replace the submodule path with the original module path. - // This ensures that the namespace's module path is reset when ownership over it is - // relinquished from the SubmoduleNamespace. - self.namespace.mod_path = std::mem::take(&mut self.parent_mod_path); - } -} diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 6b966d16b5a..a8456686124 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -435,7 +435,7 @@ impl TraitMap { name: trait_name.suffix, args: trait_type_args, }, - is_absolute: trait_name.is_absolute, + callpath_type: trait_name.callpath_type, }); // even if there is a conflicting definition, add the trait anyway @@ -1083,8 +1083,8 @@ impl TraitMap { let map_trait_name = CallPath { prefixes: entry.key.name.prefixes.clone(), suffix: entry.key.name.suffix.name.clone(), - is_absolute: entry.key.name.is_absolute, - }; + callpath_type: entry.key.name.callpath_type, + }; if &map_trait_name == trait_name { Some(entry.value.impl_span.clone()) } else { @@ -1126,7 +1126,7 @@ impl TraitMap { let map_trait_name = CallPath { prefixes: e.key.name.prefixes.clone(), suffix: e.key.name.suffix.name.clone(), - is_absolute: e.key.name.is_absolute, + callpath_type: e.key.name.callpath_type, }; if &map_trait_name == trait_name && unify_check.check(type_id, e.key.type_id) @@ -1189,7 +1189,7 @@ impl TraitMap { let trait_call_path = CallPath { prefixes: entry.key.name.prefixes.clone(), suffix: entry.key.name.suffix.name.clone(), - is_absolute: entry.key.name.is_absolute, + callpath_type: entry.key.name.callpath_type, }; trait_names.push((trait_call_path, entry.key.name.suffix.args.clone())); } @@ -1313,10 +1313,13 @@ impl TraitMap { span: symbol.span(), }, )), - Ordering::Less => Err(handler.emit_err(CompileError::SymbolNotFound { + Ordering::Less => { +// dbg!("get_trait_item_for_type"); +// dbg!(&symbol); + Err(handler.emit_err(CompileError::SymbolNotFound { name: symbol.clone(), span: symbol.span(), - })), + }))}, Ordering::Equal => Ok(candidates.values().next().unwrap().clone()), } } diff --git a/sway-core/src/semantic_analysis/symbol_collection_context.rs b/sway-core/src/semantic_analysis/symbol_collection_context.rs index 2a3be6aa35d..52057f5e979 100644 --- a/sway-core/src/semantic_analysis/symbol_collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -45,11 +45,11 @@ impl SymbolCollectionContext { ) -> (Result, LexicalScopeId) { let lexical_scope_id: LexicalScopeId = self .namespace - .module_mut(engines) + .current_module_mut() .write(engines, |m| m.push_new_lexical_scope(span.clone())); let ret = with_scoped_ctx(self); self.namespace - .module_mut(engines) + .current_module_mut() .write(engines, |m| m.pop_lexical_scope()); (ret, lexical_scope_id) } @@ -65,12 +65,14 @@ impl SymbolCollectionContext { span: Span, with_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result, ) -> Result { - self.namespace.module_mut(engines).write(engines, |m| { - m.enter_lexical_scope(handler, engines, span.clone()) - })?; + self.namespace + .current_module_mut() + .write(engines, |m| { + m.enter_lexical_scope(handler, span.clone()) + })?; let ret = with_ctx(self); self.namespace - .module_mut(engines) + .current_module_mut() .write(engines, |m| m.pop_lexical_scope()); ret } @@ -81,19 +83,20 @@ impl SymbolCollectionContext { /// Returns the result of the given `with_submod_ctx` function. pub fn enter_submodule( &mut self, - engines: &Engines, + handler: &Handler, + engines: &Engines, mod_name: Ident, visibility: Visibility, module_span: Span, with_submod_ctx: impl FnOnce(&mut SymbolCollectionContext) -> T, - ) -> T { + ) -> Result { self.namespace - .push_submodule(engines, mod_name, visibility, module_span); + .push_submodule(handler, engines, mod_name, visibility, module_span)?; //let Self { namespace, .. } = self; //let mut submod_ns = namespace.enter_submodule(mod_name, visibility, module_span); let ret = with_submod_ctx(self); self.namespace.pop_submodule(); - ret + Ok(ret) } /// Short-hand for calling [Items::insert_parsed_symbol]. @@ -104,7 +107,7 @@ impl SymbolCollectionContext { name: Ident, item: Declaration, ) -> Result<(), ErrorEmitted> { - self.namespace.module_mut(engines).write(engines, |m| { + self.namespace.current_module_mut().write(engines, |m| { m.current_items_mut().insert_parsed_symbol( handler, engines, @@ -134,10 +137,7 @@ impl SymbolCollectionContext { src: &ModulePath, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut() - .root - .star_import(handler, engines, src, &mod_path, visibility) + self.namespace_mut().star_import_to_current_module(handler, engines, src, visibility) } /// Short-hand for performing a [Module::variant_star_import] with `mod_path` as the destination. @@ -149,10 +149,7 @@ impl SymbolCollectionContext { enum_name: &Ident, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut() - .root - .variant_star_import(handler, engines, src, &mod_path, enum_name, visibility) + self.namespace_mut().variant_star_import_to_current_module(handler, engines, src, enum_name, visibility) } /// Short-hand for performing a [Module::self_import] with `mod_path` as the destination. @@ -164,10 +161,7 @@ impl SymbolCollectionContext { alias: Option, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut() - .root - .self_import(handler, engines, src, &mod_path, alias, visibility) + self.namespace_mut().self_import_to_current_module(handler, engines, src, alias, visibility) } /// Short-hand for performing a [Module::item_import] with `mod_path` as the destination. @@ -180,10 +174,7 @@ impl SymbolCollectionContext { alias: Option, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut() - .root - .item_import(handler, engines, src, item, &mod_path, alias, visibility) + self.namespace_mut().item_import_to_current_module(handler, engines, src, item, alias, visibility) } /// Short-hand for performing a [Module::variant_import] with `mod_path` as the destination. @@ -198,14 +189,12 @@ impl SymbolCollectionContext { alias: Option, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut().root.variant_import( + self.namespace_mut().variant_import_to_current_module( handler, engines, src, enum_name, variant_name, - &mod_path, alias, visibility, ) diff --git a/sway-core/src/semantic_analysis/symbol_resolve_context.rs b/sway-core/src/semantic_analysis/symbol_resolve_context.rs index 01bc631ec0e..f8ee28caf6a 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve_context.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -104,13 +104,15 @@ impl<'a> SymbolResolveContext<'a> { /// Returns the result of the given `with_submod_ctx` function. pub fn enter_submodule( self, + handler: &Handler, mod_name: Ident, visibility: Visibility, module_span: Span, with_submod_ctx: impl FnOnce(SymbolResolveContext) -> T, - ) -> T { + ) -> Result { let engines = self.engines; self.symbol_collection_ctx.enter_submodule( + handler, engines, mod_name, visibility, @@ -186,7 +188,7 @@ impl<'a> SymbolResolveContext<'a> { ) -> Result { self.resolve_call_path_with_visibility_check_and_modpath( handler, - &self.namespace().mod_path, + &self.namespace().current_mod_path, call_path, ) } @@ -205,11 +207,12 @@ impl<'a> SymbolResolveContext<'a> { mod_path: &ModulePath, call_path: &CallPath, ) -> Result { + let full_path = call_path.to_fullpath(&self.engines, &self.namespace()); let (decl, mod_path) = self.namespace().root.resolve_call_path_and_mod_path( handler, self.engines, mod_path, - call_path, + &full_path, self.self_type, )?; @@ -226,10 +229,9 @@ impl<'a> SymbolResolveContext<'a> { // check the visibility of the call path elements // we don't check the first prefix because direct children are always accessible for prefix in iter_prefixes(&call_path.prefixes).skip(1) { - let module = self.namespace().lookup_submodule_from_absolute_path( + let module = self.namespace().require_module_from_absolute_path( handler, - self.engines(), - prefix, + &prefix.to_vec(), )?; if module.visibility().is_private() { let prefix_last = prefix[prefix.len() - 1].clone(); diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 4a7e6ccf852..41e3c0f46c8 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -349,37 +349,42 @@ impl<'a> TypeCheckContext<'a> { /// /// Returns the result of the given `with_submod_ctx` function. pub fn enter_submodule( - self, + &mut self, + handler: &Handler, mod_name: Ident, visibility: Visibility, module_span: Span, with_submod_ctx: impl FnOnce(TypeCheckContext) -> T, - ) -> T { + ) -> Result { let experimental = self.experimental; // We're checking a submodule, so no need to pass through anything other than the // namespace and the engines. let engines = self.engines; - let mut submod_ns = self.namespace.enter_submodule( + self.namespace.enter_submodule( + handler, engines, mod_name.clone(), visibility, module_span.clone(), - ); + )?; self.collection_ctx.enter_submodule( + handler, engines, mod_name, visibility, module_span, - |submod_collection_ctx| { + |submod_collection_ctx| { let submod_ctx = TypeCheckContext::from_namespace( - &mut submod_ns, + &mut self.namespace, submod_collection_ctx, engines, experimental, ); - with_submod_ctx(submod_ctx) + let ret = with_submod_ctx(submod_ctx); + self.namespace.pop_submodule(); + ret }, ) } @@ -584,7 +589,7 @@ impl<'a> TypeCheckContext<'a> { where T: MonomorphizeHelper + SubstTypes, { - let mod_path = self.namespace().mod_path.clone(); + let mod_path = self.namespace().current_mod_path().clone(); monomorphize_with_modpath( handler, self.engines(), @@ -638,7 +643,7 @@ impl<'a> TypeCheckContext<'a> { let collecting_unifications = self.collecting_unifications; let engines = self.engines(); self.namespace_mut() - .module_mut(engines) + .current_module_mut() .current_items_mut() .insert_symbol( handler, @@ -660,11 +665,12 @@ impl<'a> TypeCheckContext<'a> { enforce_type_arguments: EnforceTypeArguments, type_info_prefix: Option<&ModulePath>, ) -> Result { + let mod_path = self.namespace().current_mod_path().clone(); resolve_type( handler, self.engines(), self.namespace(), - &self.namespace().mod_path, + &mod_path, type_id, span, enforce_type_arguments, @@ -684,7 +690,7 @@ impl<'a> TypeCheckContext<'a> { handler, self.engines(), self.namespace(), - &self.namespace().mod_path, + &self.namespace().current_mod_path(), call_path, self.self_type(), ) @@ -699,7 +705,7 @@ impl<'a> TypeCheckContext<'a> { handler, self.engines(), self.namespace(), - &self.namespace().mod_path.clone(), + &self.namespace().current_mod_path().clone(), qualified_call_path, self.self_type(), &self.subst_ctx(), @@ -718,6 +724,10 @@ impl<'a> TypeCheckContext<'a> { let type_engine = self.engines.te(); let _decl_engine = self.engines.de(); +// let type_name = self.engines.help_out(type_id).to_string(); +// let problem = type_name == "Bytes" && item_name.as_str() == "len"; +// if problem { dbg!(&item_prefix); }; + // If the type that we are looking for is the error recovery type, then // we want to return the error case without creating a new error // message. @@ -726,10 +736,9 @@ impl<'a> TypeCheckContext<'a> { } // grab the local module - let local_module = self.namespace().lookup_submodule_from_absolute_path( + let local_module = self.namespace().require_module_from_absolute_path( handler, - self.engines(), - &self.namespace().mod_path, + &self.namespace().current_mod_path, )?; // grab the local items from the local module @@ -737,6 +746,8 @@ impl<'a> TypeCheckContext<'a> { .current_items() .get_items_for_type(self.engines, type_id); +// if problem { dbg!(&local_items); }; + // resolve the type let type_id = resolve_type( handler, @@ -753,10 +764,9 @@ impl<'a> TypeCheckContext<'a> { .unwrap_or_else(|err| type_engine.insert(self.engines, TypeInfo::ErrorRecovery(err), None)); // grab the module where the type itself is declared - let type_module = self.namespace().lookup_submodule_from_absolute_path( + let type_module = self.namespace().require_module_from_absolute_path( handler, - self.engines(), - item_prefix, + &item_prefix.to_vec(), )?; // grab the items from where the type is declared @@ -764,6 +774,8 @@ impl<'a> TypeCheckContext<'a> { .current_items() .get_items_for_type(self.engines, type_id); +// if problem { dbg!(&type_items); }; + let mut items = local_items; items.append(&mut type_items); @@ -817,11 +829,18 @@ impl<'a> TypeCheckContext<'a> { let decl_engine = self.engines.de(); let type_engine = self.engines.te(); +// let type_name = self.engines.help_out(type_id).to_string(); +// let problem = type_name == "Bytes" && method_name.as_str() == "len"; +// if problem { +// dbg!(&method_prefix); +// } + let eq_check = UnifyCheck::non_dynamic_equality(self.engines); let coercion_check = UnifyCheck::coercion(self.engines); // default numeric types to u64 if type_engine.contains_numeric(self.engines, type_id) { +// if problem { dbg!("contains numeric"); }; // While collecting unification we don't decay numeric and will ignore this error. if self.collecting_unifications { return Err(handler.emit_err(CompileError::MethodNotFound { @@ -836,6 +855,8 @@ impl<'a> TypeCheckContext<'a> { let matching_item_decl_refs = self.find_items_for_type(handler, type_id, method_prefix, method_name)?; +// if problem { dbg!(&matching_item_decl_refs); } + let matching_method_decl_refs = matching_item_decl_refs .into_iter() .flat_map(|item| match item { @@ -845,6 +866,8 @@ impl<'a> TypeCheckContext<'a> { }) .collect::>(); +// if problem { dbg!(&matching_method_decl_refs); } + let mut qualified_call_path = None; let matching_method_decl_ref = { // Case where multiple methods exist with the same name @@ -866,6 +889,8 @@ impl<'a> TypeCheckContext<'a> { } } +// if problem { dbg!(&maybe_method_decl_refs); } + if !maybe_method_decl_refs.is_empty() { let mut trait_methods = HashMap::<(CallPath, Vec>), DeclRefFunction>::new(); @@ -1054,6 +1079,8 @@ impl<'a> TypeCheckContext<'a> { } else { self.engines.help_out(type_id).to_string() }; + // dbg!("end"); +// if problem { panic!(); }; Err(handler.emit_err(CompileError::MethodNotFound { method_name: method_name.clone(), type_name, @@ -1069,11 +1096,8 @@ impl<'a> TypeCheckContext<'a> { src: &ModulePath, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let engines = self.engines; - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut() - .root - .star_import(handler, engines, src, &mod_path, visibility) + let engines = self.engines; + self.namespace_mut().star_import_to_current_module(handler, engines, src, visibility) } /// Short-hand for performing a [Module::variant_star_import] with `mod_path` as the destination. @@ -1084,11 +1108,8 @@ impl<'a> TypeCheckContext<'a> { enum_name: &Ident, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let engines = self.engines; - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut() - .root - .variant_star_import(handler, engines, src, &mod_path, enum_name, visibility) + let engines = self.engines; + self.namespace_mut().variant_star_import_to_current_module(handler, engines, src, enum_name, visibility) } /// Short-hand for performing a [Module::self_import] with `mod_path` as the destination. @@ -1099,15 +1120,12 @@ impl<'a> TypeCheckContext<'a> { alias: Option, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let engines = self.engines; - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut() - .root - .self_import(handler, engines, src, &mod_path, alias, visibility) + let engines = self.engines; + self.namespace_mut().self_import_to_current_module(handler, engines, src, alias, visibility) } // Import all impls for a struct/enum. Do nothing for other types. - pub(crate) fn impls_import(&mut self, handler: &Handler, engines: &Engines, type_id: TypeId) { + pub(crate) fn impls_import(&mut self, engines: &Engines, type_id: TypeId) { let type_info = engines.te().get(type_id); let decl_call_path = match &*type_info { @@ -1124,8 +1142,8 @@ impl<'a> TypeCheckContext<'a> { let mut impls_to_insert = TraitMap::default(); - let root_mod = &self.namespace().root().module; - let Ok(src_mod) = root_mod.lookup_submodule(handler, engines, &decl_call_path.prefixes) + // TODO: prepend current package name? + let Some(src_mod) = &self.namespace().module_from_absolute_path(&decl_call_path.prefixes) else { return; }; @@ -1138,7 +1156,7 @@ impl<'a> TypeCheckContext<'a> { engines, ); - let dst_mod = self.namespace_mut().module_mut(engines); + let dst_mod = self.namespace_mut().current_module_mut(); dst_mod .current_items_mut() .implemented_traits @@ -1154,11 +1172,8 @@ impl<'a> TypeCheckContext<'a> { alias: Option, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let engines = self.engines; - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut() - .root - .item_import(handler, engines, src, item, &mod_path, alias, visibility) + let engines = self.engines; + self.namespace_mut().item_import_to_current_module(handler, engines, src, item, alias, visibility) } /// Short-hand for performing a [Module::variant_import] with `mod_path` as the destination. @@ -1172,15 +1187,13 @@ impl<'a> TypeCheckContext<'a> { alias: Option, visibility: Visibility, ) -> Result<(), ErrorEmitted> { - let engines = self.engines; - let mod_path = self.namespace().mod_path.clone(); - self.namespace_mut().root.variant_import( + let engines = self.engines; + self.namespace_mut().variant_import_to_current_module( handler, engines, src, enum_name, variant_name, - &mod_path, alias, visibility, ) @@ -1208,7 +1221,7 @@ impl<'a> TypeCheckContext<'a> { .map(|item| ResolvedTraitImplItem::Typed(item.clone())) .collect::>(); self.namespace_mut() - .module_mut(engines) + .current_module_mut() .current_items_mut() .implemented_traits .insert( @@ -1244,7 +1257,7 @@ impl<'a> TypeCheckContext<'a> { let trait_name = trait_name.to_fullpath(self.engines(), self.namespace()); self.namespace() - .module(self.engines()) + .current_module() .current_items() .implemented_traits .get_items_for_type_and_trait_name_and_trait_type_arguments_typed( @@ -1259,7 +1272,7 @@ impl<'a> TypeCheckContext<'a> { let engines = self.engines; let code_block_first_pass = self.code_block_first_pass(); self.namespace_mut() - .module_mut(engines) + .current_module_mut() .current_items_mut() .implemented_traits .insert_for_type(engines, type_id, code_block_first_pass.into()); @@ -1274,7 +1287,7 @@ impl<'a> TypeCheckContext<'a> { let engines = self.engines; let code_block_first_pass = self.code_block_first_pass(); self.namespace_mut() - .module_mut(engines) + .current_module_mut() .current_items_mut() .implemented_traits .check_if_trait_constraints_are_satisfied_for_type( diff --git a/sway-core/src/semantic_analysis/type_resolve.rs b/sway-core/src/semantic_analysis/type_resolve.rs index e4c676fda1e..9d13ad0e1e9 100644 --- a/sway-core/src/semantic_analysis/type_resolve.rs +++ b/sway-core/src/semantic_analysis/type_resolve.rs @@ -143,8 +143,7 @@ pub fn resolve_type( trait_type_id, } => { let trait_item_ref = namespace - .root - .module + .current_package_root_module() .current_items() .implemented_traits .get_trait_item_for_type(handler, engines, &name, trait_type_id, None)?; @@ -261,7 +260,7 @@ pub fn resolve_qualified_call_path( resolve_call_path_and_root_type_id( handler, engines, - &namespace.root.module, + &namespace.current_package_root_module(), root_type_id, as_trait_opt, &qualified_call_path.call_path, @@ -295,24 +294,21 @@ pub fn resolve_call_path( call_path: &CallPath, self_type: Option, ) -> Result { + let full_path = call_path.to_fullpath(engines, namespace); let (decl, mod_path) = namespace .root - .resolve_call_path_and_mod_path(handler, engines, mod_path, call_path, self_type)?; + .resolve_call_path_and_mod_path(handler, engines, mod_path, &full_path, self_type)?; - // In case there is no mod path we don't need to check visibility - if mod_path.is_empty() { - return Ok(decl); - } - - // In case there are no prefixes we don't need to check visibility - if call_path.prefixes.is_empty() { - return Ok(decl); + // Private declarations are visibile within their own module, so no need to check for + // visibility in that case + if mod_path == full_path.prefixes { + return Ok(decl); } // check the visibility of the call path elements // we don't check the first prefix because direct children are always accessible for prefix in iter_prefixes(&call_path.prefixes).skip(1) { - let module = namespace.lookup_submodule_from_absolute_path(handler, engines, prefix)?; + let module = namespace.require_module_from_absolute_path(handler, &prefix.to_vec())?; if module.visibility().is_private() { let prefix_last = prefix[prefix.len() - 1].clone(); handler.emit_err(CompileError::ImportPrivateModule { @@ -358,6 +354,8 @@ pub fn decl_to_type_info( (*engines.te().get(decl.type_id)).clone() } _ => { +// dbg!("decl_to_type_info"); +// dbg!(&symbol); return Err(handler.emit_err(CompileError::SymbolNotFound { name: symbol.clone(), span: symbol.span(), 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 e40c9148fda..3533f399b70 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 @@ -314,7 +314,7 @@ fn item_use_to_use_statements( fn use_tree_to_use_statements( use_tree: UseTree, - is_absolute: bool, + is_relative_to_package_root: bool, reexport: Visibility, path: &mut Vec, ret: &mut Vec, @@ -325,7 +325,7 @@ fn use_tree_to_use_statements( for use_tree in imports.into_inner() { use_tree_to_use_statements( use_tree, - is_absolute, + is_relative_to_package_root, reexport, path, ret, @@ -343,7 +343,7 @@ fn use_tree_to_use_statements( call_path: path.clone(), span: item_span, import_type, - is_absolute, + is_relative_to_package_root, reexport, alias: None, }); @@ -358,7 +358,7 @@ fn use_tree_to_use_statements( call_path: path.clone(), span: item_span, import_type, - is_absolute, + is_relative_to_package_root, reexport, alias: Some(alias), }); @@ -368,14 +368,14 @@ fn use_tree_to_use_statements( call_path: path.clone(), span: item_span, import_type: ImportType::Star, - is_absolute, + is_relative_to_package_root, reexport, alias: None, }); } UseTree::Path { prefix, suffix, .. } => { path.push(prefix); - use_tree_to_use_statements(*suffix, is_absolute, reexport, path, ret, item_span); + use_tree_to_use_statements(*suffix, is_relative_to_package_root, reexport, path, ret, item_span); path.pop().unwrap(); } UseTree::Error { .. } => { @@ -813,7 +813,7 @@ pub fn item_impl_to_declaration( let impl_self = ImplSelfOrTrait { is_self: true, trait_name: CallPath { - is_absolute: false, + callpath_type: CallPathType::Ambiguous, prefixes: vec![], suffix: BaseIdent::dummy(), }, @@ -840,14 +840,16 @@ fn path_type_to_call_path_and_type_arguments( let root_opt = path_type.root_opt.clone(); let (prefixes, suffix) = path_type_to_prefixes_and_suffix(context, handler, path_type.clone())?; - let (is_absolute, qualified_path) = + let (is_relative_to_root, qualified_path) = path_root_opt_to_bool_and_qualified_path_root(context, handler, engines, root_opt)?; + let callpath_type = if is_relative_to_root { CallPathType::RelativeToPackageRoot } else { CallPathType::Ambiguous }; + let qualified_call_path = QualifiedCallPath { call_path: CallPath { prefixes, suffix: suffix.name, - is_absolute, + callpath_type, }, qualified_path_root: qualified_path.map(Box::new), }; @@ -1559,13 +1561,16 @@ fn ty_to_call_path_tree( vec![] }; - let (is_absolute, qualified_path) = + let (is_relative_to_root, qualified_path) = path_root_opt_to_bool_and_qualified_path_root(context, handler, engines, root_opt)?; + + let callpath_type = if is_relative_to_root { CallPathType::RelativeToPackageRoot } else { CallPathType::Ambiguous }; + let call_path = QualifiedCallPath { call_path: CallPath { prefixes, suffix: suffix.name, - is_absolute, + callpath_type, }, qualified_path_root: qualified_path.map(Box::new), }; @@ -1695,7 +1700,8 @@ fn path_type_to_call_path( prefix, mut suffix, } = path_type; - let is_absolute = path_root_opt_to_bool(context, handler, root_opt)?; + let is_relative_to_root = path_root_opt_to_bool(context, handler, root_opt)?; + let callpath_type = if is_relative_to_root { CallPathType::RelativeToPackageRoot } else { CallPathType::Ambiguous }; let call_path = match suffix.pop() { Some((_double_colon_token, call_path_suffix)) => { let mut prefixes = vec![path_type_segment_to_ident(context, handler, prefix)?]; @@ -1706,13 +1712,13 @@ fn path_type_to_call_path( CallPath { prefixes, suffix: path_type_segment_to_ident(context, handler, call_path_suffix)?, - is_absolute, + callpath_type, } } None => CallPath { prefixes: Vec::new(), suffix: path_type_segment_to_ident(context, handler, prefix)?, - is_absolute, + callpath_type, }, }; Ok(call_path) @@ -1863,7 +1869,7 @@ fn expr_func_app_to_expression_kind( } }; - let (is_absolute, qualified_path_root) = + let (is_relative_to_root, qualified_path_root) = path_root_opt_to_bool_and_qualified_path_root(context, handler, engines, root_opt)?; let convert_ty_args = |context: &mut Context, generics_opt: Option<(_, GenericArgs)>| { @@ -1908,7 +1914,7 @@ fn expr_func_app_to_expression_kind( // Route intrinsic calls to different AST node. match Intrinsic::try_from_str(call_seg.name.as_str()) { Some(Intrinsic::Log) - if context.experimental.new_encoding && last.is_none() && !is_absolute => + if context.experimental.new_encoding && last.is_none() && !is_relative_to_root => { let span = name_args_span(span, type_arguments_span); return Ok(ExpressionKind::IntrinsicFunction( @@ -1926,7 +1932,7 @@ fn expr_func_app_to_expression_kind( inner: CallPath { prefixes: vec![], suffix: Ident::new_no_span("encode".into()), - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, type_arguments: TypeArgs::Regular(type_arguments), span: span.clone(), @@ -1940,7 +1946,7 @@ fn expr_func_app_to_expression_kind( }, )); } - Some(intrinsic) if last.is_none() && !is_absolute => { + Some(intrinsic) if last.is_none() && !is_relative_to_root => { return Ok(ExpressionKind::IntrinsicFunction( IntrinsicFunctionExpression { name: call_seg.name, @@ -1956,6 +1962,8 @@ fn expr_func_app_to_expression_kind( _ => {} } + let callpath_type = if is_relative_to_root { CallPathType::RelativeToPackageRoot } else { CallPathType::Ambiguous }; + // Only `foo(args)`? It could either be a function application or an enum variant. let last = match last { Some(last) => last, @@ -1967,7 +1975,7 @@ fn expr_func_app_to_expression_kind( let call_path = CallPath { prefixes, suffix, - is_absolute, + callpath_type, }; let span = match type_arguments_span { Some(span) => Span::join(call_path.span(), &span), @@ -2003,7 +2011,7 @@ fn expr_func_app_to_expression_kind( let call_path = CallPath { prefixes, suffix, - is_absolute, + callpath_type, }; let call_path_binding = TypeBinding { span: name_args_span(call_path.span(), type_arguments_span), @@ -2518,7 +2526,7 @@ fn op_call( Ident::new_with_override("ops".into(), op_span.clone()), ], suffix: Ident::new_with_override(name.into(), op_span.clone()), - is_absolute: true, + callpath_type: CallPathType::Full, }, }, type_arguments: TypeArgs::Regular(vec![]), @@ -2623,7 +2631,7 @@ fn configurable_field_to_configurable_declaration( inner: CallPath { prefixes: vec![], suffix: Ident::new_with_override("encode".into(), span.clone()), - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, type_arguments: TypeArgs::Regular(vec![type_ascription.clone()]), span: span.clone(), @@ -2798,7 +2806,8 @@ fn path_type_to_supertrait( prefix, mut suffix, } = path_type; - let is_absolute = path_root_opt_to_bool(context, handler, root_opt)?; + let is_relative_to_root = path_root_opt_to_bool(context, handler, root_opt)?; + let callpath_type = if is_relative_to_root { CallPathType::RelativeToPackageRoot } else { CallPathType::Ambiguous }; let (prefixes, call_path_suffix) = match suffix.pop() { Some((_, call_path_suffix)) => { let mut prefixes = vec![path_type_segment_to_ident(context, handler, prefix)?]; @@ -2817,7 +2826,7 @@ fn path_type_to_supertrait( let name = CallPath { prefixes, suffix, - is_absolute, + callpath_type, }; /* let type_parameters = match generics_opt { @@ -3509,8 +3518,9 @@ fn path_expr_to_qualified_call_path_binding( mut suffix, .. } = path_expr; - let (is_absolute, qualified_path_root) = + let (is_relative_to_root, qualified_path_root) = path_root_opt_to_bool_and_qualified_path_root(context, handler, engines, root_opt)?; + let callpath_type = if is_relative_to_root { CallPathType::RelativeToPackageRoot } else { CallPathType::Ambiguous }; let (prefixes, suffix, span, regular_type_arguments, prefix_type_arguments) = match suffix.pop() { Some((_, call_path_suffix)) => { @@ -3572,7 +3582,7 @@ fn path_expr_to_qualified_call_path_binding( call_path: CallPath { prefixes, suffix, - is_absolute, + callpath_type, }, qualified_path_root: qualified_path_root.map(Box::new), }, @@ -3624,7 +3634,8 @@ fn path_expr_to_call_path( mut suffix, .. } = path_expr; - let is_absolute = path_root_opt_to_bool(context, handler, root_opt)?; + let is_relative_to_root = path_root_opt_to_bool(context, handler, root_opt)?; + let callpath_type = if is_relative_to_root { CallPathType::RelativeToPackageRoot } else { CallPathType::Ambiguous }; let call_path = match suffix.pop() { Some((_double_colon_token, call_path_suffix)) => { let mut prefixes = vec![path_expr_segment_to_ident(context, handler, &prefix)?]; @@ -3635,13 +3646,13 @@ fn path_expr_to_call_path( CallPath { prefixes, suffix: path_expr_segment_to_ident(context, handler, &call_path_suffix)?, - is_absolute, + callpath_type, } } None => CallPath { prefixes: Vec::new(), suffix: path_expr_segment_to_ident(context, handler, &prefix)?, - is_absolute, + callpath_type, }, }; Ok(call_path) diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 9a4c7c1dd43..4256d542fff 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -218,9 +218,12 @@ impl TypeBinding> { let type_info_span = type_ident.span(); // find the module that the symbol is in - let type_info_prefix = ctx.namespace().prepend_module_path(&self.inner.prefixes); + // let type_info_prefix = ctx.namespace().prepend_module_path(&self.inner.prefixes); +// if self.inner.prefixes.is_empty() { +// dbg!(&self.inner); +// } ctx.namespace() - .lookup_submodule_from_absolute_path(handler, engines, &type_info_prefix)?; + .require_module_from_absolute_path(handler, &self.inner.prefixes/*&type_info_prefix*/)?; // create the type info object let type_info = type_info.apply_type_arguments( @@ -236,7 +239,7 @@ impl TypeBinding> { type_engine.insert(engines, type_info, type_info_span.source_id()), &type_info_span, EnforceTypeArguments::No, - Some(&type_info_prefix), + Some(&self.inner.prefixes /*&type_info_prefix*/), ) .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); diff --git a/sway-core/src/type_system/ast_elements/trait_constraint.rs b/sway-core/src/type_system/ast_elements/trait_constraint.rs index e91411595bb..f001c6cee0d 100644 --- a/sway-core/src/type_system/ast_elements/trait_constraint.rs +++ b/sway-core/src/type_system/ast_elements/trait_constraint.rs @@ -256,6 +256,8 @@ impl TraitConstraint { }); } _ => { +// println!("trait_constraint"); +// dbg!(&trait_name); handler.emit_err(CompileError::TraitNotFound { name: trait_name.to_string(), span: trait_name.span(), diff --git a/sway-core/src/type_system/ast_elements/type_parameter.rs b/sway-core/src/type_system/ast_elements/type_parameter.rs index 2b2ca658d23..f5dd4d757d8 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -427,7 +427,7 @@ impl TypeParameter { let sy = ctx .namespace() - .module(ctx.engines()) + .current_module() .current_items() .symbols .get(name_ident) @@ -517,7 +517,7 @@ impl TypeParameter { if !type_id.is_concrete(engines, TreatNumericAs::Concrete) && trait_constraints.len() == 1 { let concrete_trait_type_ids : Vec<(TypeId, String)>= ctx .namespace_mut() - .module(engines) + .current_module_mut() .current_items() .implemented_traits .get_trait_constraints_are_satisfied_for_types( @@ -557,11 +557,11 @@ impl TypeParameter { } // Check to see if the trait constraints are satisfied. match ctx - .namespace_mut() - .module_mut(engines) - .current_items_mut() - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( + .namespace_mut() + .current_module_mut() + .current_items_mut() + .implemented_traits + .check_if_trait_constraints_are_satisfied_for_type( handler, *type_id, trait_constraints, diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index 7a7480fe838..92b5e55f89d 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -673,7 +673,7 @@ impl TypeId { let mut found_error = false; let generic_trait_constraints_trait_names_and_args = ctx .namespace() - .module(ctx.engines()) + .current_module() .current_items() .implemented_traits .get_trait_names_and_type_arguments_for_type(engines, *structure_type_id); diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 29767d81fc0..07315510947 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -7,7 +7,7 @@ use crate::{ language::{ parsed::{EnumDeclaration, StructDeclaration}, ty::{self, TyEnumDecl, TyStructDecl}, - CallPath, QualifiedCallPath, + CallPath, CallPathType, QualifiedCallPath, }, type_system::priv_prelude::*, Ident, @@ -337,8 +337,9 @@ impl PartialEqWithEngines for TypeInfo { let l_decl = ctx.engines().de().get_enum(l_decl_ref); let r_decl = ctx.engines().de().get_enum(r_decl_ref); assert!( - l_decl.call_path.is_absolute && r_decl.call_path.is_absolute, - "The call paths of the enum declarations must always be absolute." + matches!(l_decl.call_path.callpath_type, CallPathType::Full) && + matches!(r_decl.call_path.callpath_type, CallPathType::Full), + "The call paths of the enum declarations must always be resolved." ); l_decl.call_path == r_decl.call_path && l_decl.variants.eq(&r_decl.variants, ctx) @@ -348,8 +349,9 @@ impl PartialEqWithEngines for TypeInfo { let l_decl = ctx.engines().de().get_struct(l_decl_ref); let r_decl = ctx.engines().de().get_struct(r_decl_ref); assert!( - l_decl.call_path.is_absolute && r_decl.call_path.is_absolute, - "The call paths of the struct declarations must always be absolute." + matches!(l_decl.call_path.callpath_type, CallPathType::Full) && + matches!(r_decl.call_path.callpath_type, CallPathType::Full), + "The call paths of the struct declarations must always be resolved." ); l_decl.call_path == r_decl.call_path && l_decl.fields.eq(&r_decl.fields, ctx) @@ -856,7 +858,7 @@ impl TypeInfo { call_path: CallPath { prefixes: vec![], suffix: Ident::new_with_override("Self".into(), span), - is_absolute: false, + callpath_type: CallPathType::Ambiguous, }, qualified_path_root: None, }, diff --git a/sway-core/src/type_system/unify/unify_check.rs b/sway-core/src/type_system/unify/unify_check.rs index b1e1a9db62a..80fcb861b8a 100644 --- a/sway-core/src/type_system/unify/unify_check.rs +++ b/sway-core/src/type_system/unify/unify_check.rs @@ -1,6 +1,6 @@ use crate::{ engine_threading::{Engines, PartialEqWithEngines, PartialEqWithEnginesContext}, - language::ty::{TyEnumDecl, TyStructDecl}, + language::{ty::{TyEnumDecl, TyStructDecl}, CallPathType}, type_system::{priv_prelude::*, unify::occurs_check::OccursCheck}, }; @@ -695,8 +695,9 @@ impl<'a> UnifyCheck<'a> { pub(crate) fn check_enums(&self, left: &TyEnumDecl, right: &TyEnumDecl) -> bool { assert!( - left.call_path.is_absolute && right.call_path.is_absolute, - "The call paths of the enum declarations must always be absolute." + matches!(left.call_path.callpath_type, CallPathType::Full) && + matches!(right.call_path.callpath_type, CallPathType::Full), + "The call paths of the enum declarations must always be resolved." ); // Avoid unnecessary `collect::>` of variant names @@ -755,8 +756,9 @@ impl<'a> UnifyCheck<'a> { pub(crate) fn check_structs(&self, left: &TyStructDecl, right: &TyStructDecl) -> bool { assert!( - left.call_path.is_absolute && right.call_path.is_absolute, - "The call paths of the struct declarations must always be absolute." + matches!(left.call_path.callpath_type, CallPathType::Full) && + matches!(right.call_path.callpath_type, CallPathType::Full), + "The call paths of the enum declarations must always be resolved." ); // Avoid unnecessary `collect::>` of variant names diff --git a/sway-lsp/src/capabilities/hover/hover_link_contents.rs b/sway-lsp/src/capabilities/hover/hover_link_contents.rs index 6893eb35c2d..55809689f5f 100644 --- a/sway-lsp/src/capabilities/hover/hover_link_contents.rs +++ b/sway-lsp/src/capabilities/hover/hover_link_contents.rs @@ -94,7 +94,7 @@ impl<'a> HoverLinkContents<'a> { let call_path = CallPath::from(trait_decl.name.clone()).to_fullpath(self.engines, &namespace); let impl_spans = namespace - .module(self.engines) + .current_module() .current_items() .get_impl_spans_for_trait_name(&call_path); self.add_implementations(&trait_decl.span(), impl_spans); @@ -105,7 +105,7 @@ impl<'a> HoverLinkContents<'a> { pub fn add_implementations_for_decl(&mut self, ty_decl: &TyDecl) { if let Some(namespace) = self.session.namespace() { let impl_spans = namespace - .module(self.engines) + .current_module() .current_items() .get_impl_spans_for_decl(self.engines, ty_decl); self.add_implementations(&ty_decl.span(self.engines), impl_spans); @@ -116,7 +116,7 @@ impl<'a> HoverLinkContents<'a> { pub fn add_implementations_for_type(&mut self, decl_span: &Span, type_id: TypeId) { if let Some(namespace) = self.session.namespace() { let impl_spans = namespace - .module(self.engines) + .current_module() .current_items() .get_impl_spans_for_type(self.engines, &type_id); self.add_implementations(decl_span, impl_spans); diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index fe5d59a8c9f..5c045b74111 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -231,7 +231,7 @@ impl Session { let program = compiled_program.typed.clone()?; let engines = self.engines.read(); return Some(capabilities::completion::to_completion_items( - program.root.namespace.module(&engines).current_items(), + program.root.namespace.current_module().current_items(), &engines, ident_to_complete, &fn_decl, @@ -391,7 +391,7 @@ pub fn traverse( let ctx = ParseContext::new( &session.token_map, engines, - typed_program.root.namespace.module(engines), + typed_program.root.namespace.current_module(), ); // The final element in the results is the main program. diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index 0c2745c6f21..f2eb249528a 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -103,7 +103,7 @@ impl Parse for ty::TySideEffect { span: _, import_type, alias, - is_absolute: _, + is_relative_to_package_root: _, }, ) => { for (mod_path, ident) in iter_prefixes(call_path).zip(call_path) { @@ -112,7 +112,7 @@ impl Parse for ty::TySideEffect { if let Some(span) = ctx .namespace - .submodule(ctx.engines, mod_path) + .submodule(mod_path) .and_then(|tgt_submod| tgt_submod.span().clone()) { token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); @@ -129,7 +129,7 @@ impl Parse for ty::TySideEffect { let mut type_def = None; if let Some(decl_ident) = ctx .namespace - .submodule(ctx.engines, call_path) + .submodule(call_path) .and_then(|module| module.current_items().symbols().get(item)) .and_then(|decl| { decl.expect_typed_ref().get_decl_ident(ctx.engines) @@ -168,7 +168,7 @@ impl Parse for ty::TySideEffect { Some(TypedAstToken::TypedUseStatement(use_statement.clone())); if let Some(span) = ctx .namespace - .submodule(ctx.engines, call_path) + .submodule(call_path) .and_then(|tgt_submod| tgt_submod.span().clone()) { token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); @@ -191,7 +191,7 @@ impl Parse for ty::TySideEffect { )); if let Some(span) = ctx .namespace - .submodule(ctx.engines, &[mod_name.clone()]) + .submodule(&[mod_name.clone()]) .and_then(|tgt_submod| tgt_submod.span().clone()) { token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); @@ -458,7 +458,7 @@ impl Parse for ty::TyExpression { token.typed = Some(TypedAstToken::TypedExpression(self.clone())); if let Some(abi_def_ident) = ctx .namespace - .submodule(ctx.engines, &abi_name.prefixes) + .submodule(&abi_name.prefixes) .and_then(|module| module.current_items().symbols().get(&abi_name.suffix)) .and_then(|decl| decl.expect_typed_ref().get_decl_ident(ctx.engines)) { @@ -1177,7 +1177,7 @@ fn collect_call_path_tree(ctx: &ParseContext, tree: &CallPathTree, type_arg: &Ty token.typed = Some(TypedAstToken::TypedArgument(type_arg.clone())); if let Some(abi_def_ident) = ctx .namespace - .submodule(ctx.engines, &abi_call_path.call_path.prefixes) + .submodule(&abi_call_path.call_path.prefixes) .and_then(|module| { module .current_items() @@ -1201,7 +1201,7 @@ fn collect_call_path_prefixes(ctx: &ParseContext, prefixes: &[Ident]) { token.typed = Some(TypedAstToken::Ident(ident.clone())); if let Some(span) = ctx .namespace - .submodule(ctx.engines, mod_path) + .submodule(mod_path) .and_then(|tgt_submod| tgt_submod.span().clone()) { token.kind = SymbolKind::Module; @@ -1381,7 +1381,7 @@ fn collect_trait_constraint( )); if let Some(trait_def_ident) = ctx .namespace - .submodule(ctx.engines, &trait_name.prefixes) + .submodule(&trait_name.prefixes) .and_then(|module| module.current_items().symbols().get(&trait_name.suffix)) .and_then(|decl| decl.expect_typed_ref().get_decl_ident(ctx.engines)) { diff --git a/sway-types/src/constants.rs b/sway-types/src/constants.rs index 01a3199cb1e..309dd802740 100644 --- a/sway-types/src/constants.rs +++ b/sway-types/src/constants.rs @@ -71,3 +71,5 @@ pub const VALID_ATTRIBUTE_NAMES: &[&str] = &[ pub const CORE: &str = "core"; pub const STD: &str = "std"; pub const PRELUDE: &str = "prelude"; +pub const CONTRACT_ID: &str = "CONTRACT_ID"; + diff --git a/test/src/ir_generation/mod.rs b/test/src/ir_generation/mod.rs index 8313845fe39..218cf0d6fbe 100644 --- a/test/src/ir_generation/mod.rs +++ b/test/src/ir_generation/mod.rs @@ -9,7 +9,7 @@ use anyhow::Result; use colored::Colorize; use sway_core::{ compile_ir_context_to_finalized_asm, compile_to_ast, ir_generation::compile_program, - language::Visibility, namespace, BuildTarget, Engines, + namespace, BuildTarget, Engines, }; use sway_error::handler::Handler; @@ -179,7 +179,7 @@ pub(super) async fn run( // Compile core library and reuse it when compiling tests. let engines = Engines::default(); let build_target = BuildTarget::default(); - let core_lib = compile_core(core_lib_name, build_target, &engines, run_config); + let core_root = compile_core(/*core_lib_name, */ build_target, &engines, run_config); // Find all the tests. let all_tests = discover_test_files(); @@ -239,12 +239,15 @@ pub(super) async fn run( let sway_str = String::from_utf8_lossy(&sway_str); let handler = Handler::default(); - let mut initial_namespace = namespace::Root::from(core_lib.clone()); + + let mut initial_namespace = namespace::namespace_without_contract_id(core_lib_name.clone()); + initial_namespace.add_external("core".to_owned(), core_root.clone()); + let compile_res = compile_to_ast( &handler, &engines, Arc::from(sway_str), - &mut initial_namespace, + initial_namespace, Some(&bld_cfg), PACKAGE_NAME, None, @@ -523,11 +526,11 @@ fn discover_test_files() -> Vec { } fn compile_core( - lib_name: sway_types::Ident, +// lib_name: sway_types::Ident, build_target: BuildTarget, engines: &Engines, run_config: &RunConfig, -) -> namespace::Module { +) -> namespace::Root { let manifest_dir = env!("CARGO_MANIFEST_DIR"); let libcore_root_dir = format!("{manifest_dir}/../sway-lib-core"); @@ -551,30 +554,31 @@ fn compile_core( match res.0 { Some(typed_program) => { - // Create a module for core and copy the compiled modules into it. Unfortunately we - // can't get mutable access to move them out so they're cloned. - let core_module = typed_program - .root - .namespace - .module(engines) - .submodules() - .into_iter() - .fold( - namespace::Module::new( - sway_types::Ident::new_no_span("core".to_string()), - Visibility::Private, - None, - ), - |mut core_mod, (name, sub_mod)| { - core_mod.insert_submodule(name.clone(), sub_mod.clone()); - core_mod - }, - ); - - // Create a module for std and insert the core module. - let mut std_module = namespace::Module::new(lib_name, Visibility::Private, None); - std_module.insert_submodule("core".to_owned(), core_module); - std_module +// // Create a module for core and copy the compiled modules into it. Unfortunately we +// // can't get mutable access to move them out so they're cloned. +// let core_module = typed_program +// .root +// .namespace +// .module(engines) +// .submodules() +// .into_iter() +// .fold( +// namespace::Module::new( +// sway_types::Ident::new_no_span("core".to_string()), +// Visibility::Private, +// None, +// ), +// |mut core_mod, (name, sub_mod)| { +// core_mod.insert_submodule(name.clone(), sub_mod.clone()); +// core_mod +// }, +// ); +// +// // Create a module for std and insert the core module. +// let mut std_module = namespace::Module::new(lib_name, Visibility::Private, None); +// std_module.insert_submodule("core".to_owned(), core_module); + // std_module + typed_program.root.namespace.root().clone() } _ => { let (errors, _warnings) = res.1.consume();