diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 06c517b3c2e..35985619974 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -1601,18 +1601,19 @@ pub fn dependency_namespace( ) -> Result> { // TODO: Clean this up when config-time constants v1 are removed. let node_idx = &graph[node]; - let name = Some(Ident::new_no_span(node_idx.name.clone())); + 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(), contract_id_value, experimental)? + namespace::default_with_contract_id( + engines, + name.clone(), + Visibility::Public, + contract_id_value, + experimental, + )? } else { - namespace::Module::default() + namespace::Module::new(name, Visibility::Public, None) }; - root_module.write(engines, |root_module| { - root_module.name.clone_from(&name); - root_module.visibility = Visibility::Public; - }); - // Add direct dependencies. let mut core_added = false; for edge in graph.edges_directed(node, Direction::Outgoing) { @@ -1634,16 +1635,14 @@ pub fn dependency_namespace( // Construct namespace with contract id let contract_id_value = format!("0x{dep_contract_id}"); let node_idx = &graph[dep_node]; - let name = Some(Ident::new_no_span(node_idx.name.clone())); - let mut module = namespace::default_with_contract_id( + let name = Ident::new_no_span(node_idx.name.clone()); + namespace::default_with_contract_id( engines, name.clone(), + Visibility::Private, contract_id_value, experimental, - )?; - module.name = name; - module.visibility = Visibility::Public; - module + )? } }; dep_namespace.is_external = true; @@ -2481,9 +2480,6 @@ pub fn build( } if let TreeType::Library = compiled.tree_type { - compiled.root_module.write(&engines, |root_module| { - root_module.name = Some(Ident::new_no_span(pkg.name.clone())); - }); lib_namespace_map.insert(node, compiled.root_module); } source_map.insert_dependency(descriptor.manifest_file.dir()); @@ -2737,8 +2733,7 @@ pub fn check( .namespace .program_id(engines) .read(engines, |m| m.clone()); - module.name = Some(Ident::new_no_span(pkg.name.clone())); - module.span = Some( + module.set_span( Span::new( manifest.entry_string()?, 0, diff --git a/sway-core/src/abi_generation/abi_str.rs b/sway-core/src/abi_generation/abi_str.rs index bc3618abac3..b52af834f0c 100644 --- a/sway-core/src/abi_generation/abi_str.rs +++ b/sway-core/src/abi_generation/abi_str.rs @@ -3,7 +3,7 @@ use sway_types::integer_bits::IntegerBits; use crate::{language::CallPath, Engines, TypeArgument, TypeId, TypeInfo}; pub struct AbiStrContext { - pub program_name: Option, + pub program_name: String, pub abi_with_callpaths: bool, pub abi_with_fully_specified_types: bool, } @@ -182,9 +182,8 @@ fn call_path_display(ctx: &AbiStrContext, call_path: &CallPath) -> String { return call_path.suffix.as_str().to_string(); } let mut buf = String::new(); - let root_name = ctx.program_name.as_deref(); for (index, prefix) in call_path.prefixes.iter().enumerate() { - if index == 0 && Some(prefix.as_str()) == root_name { + if index == 0 && prefix.as_str() == ctx.program_name { continue; } buf.push_str(prefix.as_str()); diff --git a/sway-core/src/abi_generation/fuel_abi.rs b/sway-core/src/abi_generation/fuel_abi.rs index 1479dd2c155..f49e8eb6fea 100644 --- a/sway-core/src/abi_generation/fuel_abi.rs +++ b/sway-core/src/abi_generation/fuel_abi.rs @@ -26,7 +26,7 @@ impl<'a> AbiContext<'a> { .root .namespace .program_id(engines) - .read(engines, |m| m.name.clone().map(|v| v.as_str().to_string())), + .read(engines, |m| m.name().to_string()), abi_with_callpaths: self.abi_with_callpaths, abi_with_fully_specified_types, } diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index f16e36e5b97..157d103589e 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -1316,12 +1316,11 @@ mod tests { }, ); let mut md_mgr = MetadataManager::default(); - let mut core_lib = namespace::Root::from(namespace::Module { - name: Some(sway_types::Ident::new_no_span( - "assert_is_constant_test".to_string(), - )), - ..Default::default() - }); + let mut core_lib = namespace::Root::from(namespace::Module::new( + sway_types::Ident::new_no_span("assert_is_constant_test".to_string()), + crate::Visibility::Private, + None, + )); let r = crate::compile_to_ast( &handler, diff --git a/sway-core/src/language/call_path.rs b/sway-core/src/language/call_path.rs index e71cef0aa93..7c6ba2502f7 100644 --- a/sway-core/src/language/call_path.rs +++ b/sway-core/src/language/call_path.rs @@ -336,9 +336,7 @@ 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(); - if let Some(ref pkg_name) = namespace.root_module().name { - res.prefixes.push(pkg_name.clone()) - }; + res.prefixes.push(namespace.root_module().name().clone()); for mod_path in namespace.mod_path() { res.prefixes.push(mod_path.clone()) } @@ -404,9 +402,7 @@ impl CallPath { let mut prefixes: Vec = vec![]; if !is_external { - if let Some(pkg_name) = &namespace.root_module().name { - prefixes.push(pkg_name.clone()); - } + prefixes.push(namespace.root_module().name().clone()); if !is_absolute { for mod_path in namespace.mod_path() { @@ -439,9 +435,8 @@ impl CallPath { } } else { let mut prefixes: Vec = vec![]; - if let Some(pkg_name) = &namespace.root_module().read(engines, |m| m.name.clone()) { - prefixes.push(pkg_name.clone()); - } + prefixes.push(namespace.root_module().name().clone()); + for mod_path in namespace.mod_path() { prefixes.push(mod_path.clone()); } @@ -473,7 +468,7 @@ impl CallPath { let converted = self.to_fullpath(engines, namespace); if let Some(first) = converted.prefixes.first() { - if namespace.root_module().read(engines, |m| m.name.clone()) == Some(first.clone()) { + if namespace.root_module().name() == first { return converted.lshift(); } } diff --git a/sway-core/src/language/ty/expression/intrinsic_function.rs b/sway-core/src/language/ty/expression/intrinsic_function.rs index a82ec310f9f..2d9466d3c0c 100644 --- a/sway-core/src/language/ty/expression/intrinsic_function.rs +++ b/sway-core/src/language/ty/expression/intrinsic_function.rs @@ -118,7 +118,7 @@ impl CollectTypesMetadata for TyIntrinsicFunctionKind { types_metadata.push(TypeMetadata::LoggedType( LogId::new(logged_type.get_abi_type_str( &AbiStrContext { - program_name: Some(ctx.program_name.clone()), + program_name: ctx.program_name.clone(), abi_with_callpaths: true, abi_with_fully_specified_types: true, }, diff --git a/sway-core/src/language/ty/expression/scrutinee.rs b/sway-core/src/language/ty/expression/scrutinee.rs index 240865dcda3..68c51af26eb 100644 --- a/sway-core/src/language/ty/expression/scrutinee.rs +++ b/sway-core/src/language/ty/expression/scrutinee.rs @@ -20,7 +20,6 @@ pub enum TyScrutineeVariant { Literal(Literal), Variable(Ident), Constant(Ident, Literal, TyConstantDecl), - Configurable(Ident, Literal, TyConfigurableDecl), StructScrutinee { struct_ref: DeclRefStruct, fields: Vec, 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 efb07857886..2731811f6a7 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 @@ -401,8 +401,7 @@ where engines: &Engines, decl: &TyDecl, ) -> Option<(Option, Option)> { - if matches!(self.ctx.namespace.root().module.read(engines, |m| m.name.clone()).as_ref(), Some(x) if x.as_str() == "core") - { + if self.ctx.namespace.root().module.name().as_str() == "core" { return Some((None, None)); } @@ -437,8 +436,7 @@ where engines: &Engines, decl: &TyDecl, ) -> Option<(Option, Option)> { - if matches!(self.ctx.namespace.root().module.read(engines, |m| m.name.clone()).as_ref(), Some(x) if x.as_str() == "core") - { + if self.ctx.namespace.root().module.name().as_str() == "core" { return Some((None, None)); } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/duplicates.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/match_pattern_variables.rs similarity index 82% rename from sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/duplicates.rs rename to sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/match_pattern_variables.rs index f368e01eeec..0e08b8b4371 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/duplicates.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/match_pattern_variables.rs @@ -175,7 +175,6 @@ pub(crate) fn collect_duplicate_match_pattern_variables( ty::TyScrutineeVariant::Variable(ident) => add_variable(left_most_branch, ident, false), ty::TyScrutineeVariant::Literal(_) => (), ty::TyScrutineeVariant::Constant { .. } => (), - ty::TyScrutineeVariant::Configurable { .. } => (), ty::TyScrutineeVariant::StructScrutinee { fields, .. } => { // If a field does not have a scrutinee, the field itself is a variable. for field in fields { @@ -247,3 +246,49 @@ pub(crate) fn collect_duplicate_match_pattern_variables( } } } + +/// Returns [Ident]s for all match arm variables found in the `scrutinee`, +/// together with the information if the variable is a struct field (true) +/// or not (false), or empty [Vec] if there are no variables declared in +/// the `scrutinee`. +/// +/// If the `scrutinee` contains alternatives, and thus a variable is declared +/// multiple times, each occurrence of the variable will be returned. +pub(crate) fn collect_match_pattern_variables(scrutinee: &TyScrutinee) -> Vec<(Ident, bool)> { + let mut variables = vec![]; + + recursively_collect_variables(&mut variables, scrutinee); + + return variables; + + fn recursively_collect_variables(variables: &mut Vec<(Ident, bool)>, scrutinee: &TyScrutinee) { + match &scrutinee.variant { + ty::TyScrutineeVariant::CatchAll => (), + ty::TyScrutineeVariant::Variable(ident) => variables.push((ident.clone(), false)), + ty::TyScrutineeVariant::Literal(_) => (), + ty::TyScrutineeVariant::Constant { .. } => (), + ty::TyScrutineeVariant::StructScrutinee { fields, .. } => { + // If a field does not have a scrutinee, the field itself is a variable. + for field in fields { + match &field.scrutinee { + Some(scrutinee) => recursively_collect_variables(variables, scrutinee), + None => variables.push((field.field.clone(), true)), + } + } + } + ty::TyScrutineeVariant::Or(scrutinees) => { + for scrutinee in scrutinees { + recursively_collect_variables(variables, scrutinee); + } + } + ty::TyScrutineeVariant::Tuple(scrutinees) => { + for scrutinee in scrutinees { + recursively_collect_variables(variables, scrutinee); + } + } + ty::TyScrutineeVariant::EnumScrutinee { value, .. } => { + recursively_collect_variables(variables, value) + } + } + } +} diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/mod.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/mod.rs index ab43e75ec12..251672fa95f 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/mod.rs @@ -1,5 +1,5 @@ mod constructor_factory; -mod duplicates; +mod match_pattern_variables; mod matrix; mod patstack; mod pattern; @@ -8,6 +8,8 @@ mod reachable_report; mod usefulness; mod witness_report; -pub(crate) use duplicates::collect_duplicate_match_pattern_variables; +pub(crate) use match_pattern_variables::{ + collect_duplicate_match_pattern_variables, collect_match_pattern_variables, +}; pub(in crate::semantic_analysis::ast_node::expression) use reachable_report::ReachableReport; pub(crate) use usefulness::check_match_expression_usefulness; diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/pattern.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/pattern.rs index 3a0458d4fed..7de4cc88dc4 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/pattern.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/analysis/pattern.rs @@ -120,7 +120,6 @@ impl Pattern { ty::TyScrutineeVariant::Variable(_) => Pattern::Wildcard, ty::TyScrutineeVariant::Literal(value) => Pattern::from_literal(value), ty::TyScrutineeVariant::Constant(_, value, _) => Pattern::from_literal(value), - ty::TyScrutineeVariant::Configurable(_, value, _) => Pattern::from_literal(value), ty::TyScrutineeVariant::StructScrutinee { struct_ref, fields, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs index b36cef5600e..39cd872146d 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs @@ -2,7 +2,7 @@ use indexmap::IndexMap; use crate::{ language::{ - ty::{self, TyConfigurableDecl, TyConstantDecl}, + ty::{self, TyConstantDecl}, CallPath, Literal, }, semantic_analysis::{ @@ -229,9 +229,6 @@ pub(super) fn matcher( ty::TyScrutineeVariant::Constant(_, _, const_decl) => { Ok(match_constant(ctx, exp, const_decl, span)) } - ty::TyScrutineeVariant::Configurable(_, _, config_decl) => { - Ok(match_configurable(ctx, exp, config_decl, span)) - } ty::TyScrutineeVariant::StructScrutinee { struct_ref: _, fields, @@ -422,31 +419,6 @@ fn match_constant( ReqDeclTree::req(req) } -fn match_configurable( - ctx: TypeCheckContext, - exp: &ty::TyExpression, - decl: TyConfigurableDecl, - span: Span, -) -> ReqDeclTree { - let name = decl.name().clone(); - let return_type = decl.type_ascription.type_id; - - let req = ( - exp.to_owned(), - ty::TyExpression { - expression: ty::TyExpressionVariant::ConfigurableExpression { - span: span.clone(), - decl: Box::new(decl), - call_path: Some(CallPath::from(name).to_fullpath(ctx.engines(), ctx.namespace())), - }, - return_type, - span, - }, - ); - - ReqDeclTree::req(req) -} - fn match_struct( handler: &Handler, mut ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs index 254e98cd5c9..0a1c3870106 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs @@ -1,7 +1,8 @@ use ast_node::expression::match_expression::typed::matcher::{ReqDeclNode, ReqOrVarDecl}; +use indexmap::IndexSet; use itertools::{multiunzip, Itertools}; use sway_error::{ - error::CompileError, + error::{CompileError, ShadowingSource}, handler::{ErrorEmitted, Handler}, }; use sway_types::{Ident, Span, Spanned}; @@ -43,10 +44,10 @@ impl ty::TyMatchBranch { let type_engine = ctx.engines.te(); let engines = ctx.engines(); - // type check the scrutinee + // Type check the scrutinee. let typed_scrutinee = ty::TyScrutinee::type_check(handler, ctx.by_ref(), scrutinee)?; - // calculate the requirements and variable declarations + // Calculate the requirements and variable declarations. let req_decl_tree = matcher( handler, ctx.by_ref(), @@ -76,6 +77,48 @@ impl ty::TyMatchBranch { Ok(()) })?; + // Emit errors for eventual uses of configurables in patterns. + // Configurables cannot be used in pattern matching, since they are not compile-time + // constants. Using a configurable will define a pattern variable, that will + // then shadow the configurable of the same name, which is not allowed. + // This can be very confusing in case someone tries to use configurables in pattern matching + // in the same way as constants. So we provide helpful hints here. + // We stop further compilation in case of finding configurables in patterns. + handler.scope(|handler| { + // All the first occurrences of variables in order of appearance, while respecting + // if they are struct field variables. + let variables: IndexSet<(Ident, bool)> = + IndexSet::from_iter(collect_match_pattern_variables(&typed_scrutinee)); + for (ident, is_struct_field) in variables { + let default_handler = &Handler::default(); + // If there exist a configurable with the same name as the pattern variable. + if let Ok(ty::TyDecl::ConfigurableDecl(configurable_decl)) = ctx + .namespace() + .resolve_symbol_typed(default_handler, engines, &ident, ctx.self_type()) + { + let name = (&ident).into(); + let configurable_span = engines + .de() + .get_configurable(&configurable_decl.decl_id) + .span(); + if is_struct_field { + handler.emit_err(CompileError::ConfigurablesCannotBeShadowed { + shadowing_source: ShadowingSource::PatternMatchingStructFieldVar, + name, + configurable_span, + }); + } else { + handler.emit_err(CompileError::ConfigurablesCannotBeMatchedAgainst { + name, + configurable_span, + }); + } + } + } + + Ok(()) + })?; + let (condition, result_var_declarations, or_variant_vars) = instantiate_branch_condition_result_var_declarations_and_matched_or_variant_index_vars( handler, 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 715e6e21da2..4f726c3b711 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 @@ -143,7 +143,6 @@ impl TyScrutinee { ty::TyScrutineeVariant::Variable(_) => true, ty::TyScrutineeVariant::Literal(_) => false, ty::TyScrutineeVariant::Constant { .. } => false, - ty::TyScrutineeVariant::Configurable { .. } => false, ty::TyScrutineeVariant::StructScrutinee { fields, .. } => fields .iter() .filter_map(|x| x.scrutinee.as_ref()) @@ -155,6 +154,8 @@ impl TyScrutinee { } } +/// Type checks the `name`, assuming that it's either a variable or an ambiguous identifier +/// that might be a constant or configurable. fn type_check_variable( handler: &Handler, ctx: TypeCheckContext, @@ -170,14 +171,14 @@ fn type_check_variable( .resolve_symbol_typed(&Handler::default(), engines, &name, ctx.self_type()) .ok() { - // If this variable is a constant, then we turn it into a [TyScrutinee::Constant](ty::TyScrutinee::Constant). + // If the name represents a constant, then we turn it into a [ty::TyScrutineeVariant::Constant]. Some(ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. })) => { let constant_decl = (*decl_engine.get_constant(&decl_id)).clone(); let value = match constant_decl.value { Some(ref value) => value, None => { return Err(handler.emit_err(CompileError::Internal( - "constant value does not contain expression", + "Constant value does not contain expression", span, ))); } @@ -198,7 +199,15 @@ fn type_check_variable( span, } } - // Variable isn't a constant, so we turn it into a [ty::TyScrutinee::Variable]. + // If the name isn't a constant, we turn it into a [ty::TyScrutineeVariant::Variable]. + // + // Note that the declaration could be a configurable declaration, [ty::ConfigurableDecl]. + // Configurables cannot be matched against, but we do not emit that error here. + // That would unnecessary short-circuit the compilation and reduce number of errors + // collected. + // Rather, we consider the configurable to be a pattern variable declaration, which + // strictly speaking it is. Later when checking typed match arm, we will emit + // appropriate helpful errors, depending on the exact usage of that configurable. _ => ty::TyScrutinee { variant: ty::TyScrutineeVariant::Variable(name), type_id: type_engine.insert(ctx.engines(), TypeInfo::Unknown, None), 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 88a027a343a..e5f5ca57586 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 @@ -2680,7 +2680,12 @@ mod tests { type_annotation: TypeId, experimental: ExperimentalFlags, ) -> Result { - let mut root_module = namespace::Root::from(namespace::Module::default()); + let root_module_name = sway_types::Ident::new_no_span("do_type_check_test".to_string()); + let mut root_module = namespace::Root::from(namespace::Module::new( + root_module_name, + Visibility::Private, + None, + )); let mut namespace = Namespace::init_root(&mut root_module); let ctx = TypeCheckContext::from_namespace(&mut namespace, engines, experimental) .with_type_annotation(type_annotation); 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 04e88818497..c281e67da0e 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 @@ -829,7 +829,7 @@ pub(crate) fn resolve_method_name( ctx.namespace().prepend_module_path(&call_path.prefixes) } else { let mut module_path = call_path.prefixes.clone(); - if let (Some(root_mod), Some(root_name)) = ( + if let (Some(root_mod), root_name) = ( module_path.first().cloned(), ctx.namespace().root_module_name().clone(), ) { diff --git a/sway-core/src/semantic_analysis/namespace/contract_helpers.rs b/sway-core/src/semantic_analysis/namespace/contract_helpers.rs index eaa91f37820..9a58cd80c64 100644 --- a/sway-core/src/semantic_analysis/namespace/contract_helpers.rs +++ b/sway-core/src/semantic_analysis/namespace/contract_helpers.rs @@ -26,25 +26,34 @@ use super::{lexical_scope::SymbolMap, root::ResolvedDeclaration, Module, Root}; /// `CONTRACT_ID`-containing modules: https://github.com/FuelLabs/sway/issues/3077 pub fn default_with_contract_id( engines: &Engines, - name: Option, + name: Ident, + visibility: Visibility, contract_id_value: String, experimental: crate::ExperimentalFlags, ) -> 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()); + 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() - }) + // 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: Option, + ns_name: Ident, + visibility: Visibility, contract_id_value: String, experimental: crate::ExperimentalFlags, ) -> Result { @@ -95,11 +104,9 @@ 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::default()); + let mut root = Root::from(Module::new(ns_name.clone(), Visibility::Public, None)); 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 - ns.root.module.name = ns_name; - ns.root.module.visibility = Visibility::Public; 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: @@ -118,7 +125,7 @@ fn default_with_contract_id_inner( }; compiled_constants.insert(name, ResolvedDeclaration::Typed(typed_decl)); - let mut ret = Module::default(); + 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 e82bf24846c..f327269eee2 100644 --- a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs +++ b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs @@ -14,7 +14,7 @@ use crate::{ use super::{root::ResolvedDeclaration, TraitMap}; use sway_error::{ - error::{CompileError, StructFieldUsageContext}, + error::{CompileError, ShadowingSource, StructFieldUsageContext}, handler::{ErrorEmitted, Handler}, }; use sway_types::{span::Span, Spanned}; @@ -215,6 +215,13 @@ impl Items { const_shadowing_mode, generic_shadowing_mode, ) { + // A general remark for using the `ShadowingSource::LetVar`. + // If the shadowing is detected at this stage, the variable is for + // sure a local variable, because in the case of pattern matching + // struct field variables, the error is already reported and + // the compilation do not proceed to the point of inserting + // the pattern variable into the items. + // variable shadowing a constant ( constant_ident, @@ -226,10 +233,10 @@ impl Items { _, ) => { handler.emit_err(CompileError::ConstantsCannotBeShadowed { - variable_or_constant: "Variable".to_string(), + shadowing_source: ShadowingSource::LetVar, name: (&name).into(), constant_span: constant_ident.span(), - constant_decl: if is_imported_constant { + constant_decl_span: if is_imported_constant { parsed_decl_engine.get(decl_id).span.clone() } else { Span::dummy() @@ -237,6 +244,22 @@ impl Items { is_alias, }); } + // variable shadowing a configurable + ( + configurable_ident, + ConfigurableDeclaration(_), + _, + _, + VariableDeclaration { .. }, + _, + _, + ) => { + handler.emit_err(CompileError::ConfigurablesCannotBeShadowed { + shadowing_source: ShadowingSource::LetVar, + name: (&name).into(), + configurable_span: configurable_ident.span(), + }); + } // constant shadowing a constant sequentially ( constant_ident, @@ -248,10 +271,10 @@ impl Items { _, ) => { handler.emit_err(CompileError::ConstantsCannotBeShadowed { - variable_or_constant: "Constant".to_string(), + shadowing_source: ShadowingSource::Const, name: (&name).into(), constant_span: constant_ident.span(), - constant_decl: if is_imported_constant { + constant_decl_span: if is_imported_constant { parsed_decl_engine.get(decl_id).span.clone() } else { Span::dummy() @@ -259,6 +282,22 @@ impl Items { is_alias, }); } + // constant shadowing a configurable sequentially + ( + configurable_ident, + ConfigurableDeclaration(_), + _, + _, + ConstantDeclaration { .. }, + ConstShadowingMode::Sequential, + _, + ) => { + handler.emit_err(CompileError::ConfigurablesCannotBeShadowed { + shadowing_source: ShadowingSource::Const, + name: (&name).into(), + configurable_span: configurable_ident.span(), + }); + } // constant shadowing a variable (_, VariableDeclaration(decl_id), _, _, ConstantDeclaration { .. }, _, _) => { handler.emit_err(CompileError::ConstantShadowsVariable { @@ -268,17 +307,53 @@ impl Items { } // constant shadowing a constant item-style (outside of a function body) ( + constant_ident, + ConstantDeclaration { .. }, + _, _, ConstantDeclaration { .. }, + ConstShadowingMode::ItemStyle, + _, + ) => { + handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable { + existing_constant_or_configurable: "Constant", + new_constant_or_configurable: "Constant", + name: (&name).into(), + existing_span: constant_ident.span(), + }); + } + // constant shadowing a configurable item-style (outside of a function body) + ( + configurable_ident, + ConfigurableDeclaration { .. }, _, _, ConstantDeclaration { .. }, ConstShadowingMode::ItemStyle, _, ) => { - handler.emit_err(CompileError::MultipleDefinitionsOfConstant { - name: name.clone(), - span: name.span(), + handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable { + existing_constant_or_configurable: "Configurable", + new_constant_or_configurable: "Constant", + name: (&name).into(), + existing_span: configurable_ident.span(), + }); + } + // configurable shadowing a constant item-style (outside of a function body) + ( + constant_ident, + ConstantDeclaration { .. }, + _, + _, + ConfigurableDeclaration { .. }, + ConstShadowingMode::ItemStyle, + _, + ) => { + handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable { + existing_constant_or_configurable: "Constant", + new_constant_or_configurable: "Configurable", + name: (&name).into(), + existing_span: constant_ident.span(), }); } // type or type alias shadowing another type or type alias @@ -327,6 +402,13 @@ impl Items { const_shadowing_mode, generic_shadowing_mode, ) { + // A general remark for using the `ShadowingSource::LetVar`. + // If the shadowing is detected at this stage, the variable is for + // sure a local variable, because in the case of pattern matching + // struct field variables, the error is already reported and + // the compilation do not proceed to the point of inserting + // the pattern variable into the items. + // variable shadowing a constant ( constant_ident, @@ -338,10 +420,10 @@ impl Items { _, ) => { handler.emit_err(CompileError::ConstantsCannotBeShadowed { - variable_or_constant: "Variable".to_string(), + shadowing_source: ShadowingSource::LetVar, name: (&name).into(), constant_span: constant_ident.span(), - constant_decl: if is_imported_constant { + constant_decl_span: if is_imported_constant { decl_engine.get(&constant_decl.decl_id).span.clone() } else { Span::dummy() @@ -349,6 +431,14 @@ impl Items { is_alias, }); } + // variable shadowing a configurable + (configurable_ident, ConfigurableDecl(_), _, _, VariableDecl { .. }, _, _) => { + handler.emit_err(CompileError::ConfigurablesCannotBeShadowed { + shadowing_source: ShadowingSource::LetVar, + name: (&name).into(), + configurable_span: configurable_ident.span(), + }); + } // constant shadowing a constant sequentially ( constant_ident, @@ -360,10 +450,10 @@ impl Items { _, ) => { handler.emit_err(CompileError::ConstantsCannotBeShadowed { - variable_or_constant: "Constant".to_string(), + shadowing_source: ShadowingSource::Const, name: (&name).into(), constant_span: constant_ident.span(), - constant_decl: if is_imported_constant { + constant_decl_span: if is_imported_constant { decl_engine.get(&constant_decl.decl_id).span.clone() } else { Span::dummy() @@ -371,6 +461,22 @@ impl Items { is_alias, }); } + // constant shadowing a configurable sequentially + ( + configurable_ident, + ConfigurableDecl(_), + _, + _, + ConstantDecl { .. }, + ConstShadowingMode::Sequential, + _, + ) => { + handler.emit_err(CompileError::ConfigurablesCannotBeShadowed { + shadowing_source: ShadowingSource::Const, + name: (&name).into(), + configurable_span: configurable_ident.span(), + }); + } // constant shadowing a variable (_, VariableDecl(variable_decl), _, _, ConstantDecl { .. }, _, _) => { handler.emit_err(CompileError::ConstantShadowsVariable { @@ -380,17 +486,53 @@ impl Items { } // constant shadowing a constant item-style (outside of a function body) ( + constant_ident, + ConstantDecl { .. }, + _, _, ConstantDecl { .. }, + ConstShadowingMode::ItemStyle, + _, + ) => { + handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable { + existing_constant_or_configurable: "Constant", + new_constant_or_configurable: "Constant", + name: (&name).into(), + existing_span: constant_ident.span(), + }); + } + // constant shadowing a configurable item-style (outside of a function body) + ( + configurable_ident, + ConfigurableDecl { .. }, _, _, ConstantDecl { .. }, ConstShadowingMode::ItemStyle, _, ) => { - handler.emit_err(CompileError::MultipleDefinitionsOfConstant { - name: name.clone(), - span: name.span(), + handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable { + existing_constant_or_configurable: "Configurable", + new_constant_or_configurable: "Constant", + name: (&name).into(), + existing_span: configurable_ident.span(), + }); + } + // configurable shadowing a constant item-style (outside of a function body) + ( + constant_ident, + ConstantDecl { .. }, + _, + _, + ConfigurableDecl { .. }, + ConstShadowingMode::ItemStyle, + _, + ) => { + handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable { + existing_constant_or_configurable: "Constant", + new_constant_or_configurable: "Configurable", + name: (&name).into(), + existing_span: constant_ident.span(), }); } // type or type alias shadowing another type or type alias diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index b61daaa2c01..bfa1f683945 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -36,11 +36,11 @@ pub struct Module { pub current_lexical_scope_id: LexicalScopeId, /// Name of the module, package name for root module, module name for other modules. /// Module name used is the same as declared in `mod name;`. - pub name: Option, + name: Ident, /// Whether or not this is a `pub` module - pub visibility: Visibility, + visibility: Visibility, /// Empty span at the beginning of the file implementing the module - pub span: Option, + 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, @@ -51,22 +51,57 @@ pub struct Module { pub(crate) mod_path: ModulePathBuf, } -impl Default for Module { - fn default() -> Self { +impl Module { + pub fn new(name: Ident, visibility: Visibility, span: Option) -> Self { Self { - visibility: Visibility::Private, + visibility, submodules: Default::default(), lexical_scopes: vec![LexicalScope::default()], current_lexical_scope_id: 0, - name: Default::default(), - span: Default::default(), + name, + span, is_external: Default::default(), mod_path: Default::default(), } } -} -impl Module { + // 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(), + current_lexical_scope_id: self.current_lexical_scope_id, + name, + span, + is_external, + mod_path, + } + } + + pub fn name(&self) -> &Ident { + &self.name + } + + pub fn visibility(&self) -> &Visibility { + &self.visibility + } + + pub fn span(&self) -> &Option { + &self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = Some(span); + } + pub fn read(&self, _engines: &crate::Engines, mut f: impl FnMut(&Module) -> R) -> R { f(self) } diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 9b2470bb3d3..7a8b00e4304 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -110,8 +110,8 @@ impl Namespace { } /// The name of the root module - pub fn root_module_name(&self) -> &Option { - &self.root.module.name + pub fn root_module_name(&self) -> &Ident { + self.root.module.name() } /// Access to the current [Module], i.e. the module at the inner `mod_path`. @@ -158,10 +158,7 @@ impl Namespace { ) -> 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 = match &self.root.module.name { - Some(name) => name, - None => panic!("Root module must always have a 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."); @@ -192,10 +189,7 @@ 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 = match &self.root.module.name { - Some(name) => name, - None => panic!("Root module must always have a name."), - }; + 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."); @@ -292,24 +286,23 @@ impl Namespace { ) -> SubmoduleNamespace { let init = self.init.clone(); let is_external = self.module(engines).is_external; - self.module_mut(engines) - .submodules - .entry(mod_name.to_string()) - .or_insert(init); 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()); - // self.module() now refers to a different module, so refetch - let new_module = self.module_mut(engines); - new_module.name = Some(mod_name); - new_module.span = Some(module_span); - new_module.visibility = visibility; - new_module.is_external = is_external; - new_module.mod_path = submod_path; SubmoduleNamespace { namespace: self, parent_mod_path, @@ -324,16 +317,10 @@ impl Namespace { visibility: Visibility, module_span: Span, ) { - let module = Module { - name: Some(mod_name.clone()), - visibility, - span: Some(module_span), - ..Default::default() - }; self.module_mut(engines) .submodules .entry(mod_name.to_string()) - .or_insert(module); + .or_insert(Module::new(mod_name.clone(), visibility, Some(module_span))); self.mod_path.push(mod_name); } diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 960909134ef..31480d5567a 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -668,7 +668,7 @@ impl Root { // 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() { + if module.visibility().is_private() { let prefix_last = prefix[prefix.len() - 1].clone(); handler.emit_err(CompileError::ImportPrivateModule { span: prefix_last.span(), diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index daddfdaa947..621c8e8d838 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -774,7 +774,7 @@ impl<'a> TypeCheckContext<'a> { let module = self .namespace() .lookup_submodule_from_absolute_path(handler, engines, prefix)?; - if module.visibility.is_private() { + if module.visibility().is_private() { let prefix_last = prefix[prefix.len() - 1].clone(); handler.emit_err(CompileError::ImportPrivateModule { span: prefix_last.span(), diff --git a/sway-error/src/diagnostic.rs b/sway-error/src/diagnostic.rs index d301bebffaa..ddfe86bfb92 100644 --- a/sway-error/src/diagnostic.rs +++ b/sway-error/src/diagnostic.rs @@ -307,24 +307,56 @@ impl Hint { } } + pub fn multi_info(source_engine: &SourceEngine, span: &Span, hints: Vec) -> Vec { + hints + .into_iter() + .map(|hint| Self::info(source_engine, span.clone(), hint)) + .collect() + } + pub fn help(source_engine: &SourceEngine, span: Span, text: String) -> Self { Self { label: Label::help(source_engine, span, text), } } + pub fn multi_help(source_engine: &SourceEngine, span: &Span, hints: Vec) -> Vec { + hints + .into_iter() + .map(|hint| Self::help(source_engine, span.clone(), hint)) + .collect() + } + pub fn warning(source_engine: &SourceEngine, span: Span, text: String) -> Self { Self { label: Label::warning(source_engine, span, text), } } + pub fn multi_warning( + source_engine: &SourceEngine, + span: &Span, + hints: Vec, + ) -> Vec { + hints + .into_iter() + .map(|hint| Self::warning(source_engine, span.clone(), hint)) + .collect() + } + pub fn error(source_engine: &SourceEngine, span: Span, text: String) -> Self { Self { label: Label::error(source_engine, span, text), } } + pub fn multi_error(source_engine: &SourceEngine, span: &Span, hints: Vec) -> Vec { + hints + .into_iter() + .map(|hint| Self::error(source_engine, span.clone(), hint)) + .collect() + } + /// A [Hint] that will never be displayed. Convenient when defining [Hint]s that /// are displayed only if a condition is met. pub fn none() -> Self { diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index a2bec9fc219..45c42c222dd 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -12,6 +12,7 @@ use sway_types::style::to_snake_case; use sway_types::{BaseIdent, Ident, IdentUnique, SourceEngine, Span, Spanned}; use thiserror::Error; +use self::ShadowingSource::*; use self::StructFieldUsageContext::*; #[derive(Error, Debug, Clone, PartialEq, Eq, Hash)] @@ -664,20 +665,58 @@ pub enum CompileError { span: Span, prefix_span: Span, }, - #[error("Constants cannot be shadowed. {variable_or_constant} \"{name}\" shadows constant with the same name.")] + #[error("Constants cannot be shadowed. {shadowing_source} \"{name}\" shadows constant of the same name.")] ConstantsCannotBeShadowed { - variable_or_constant: String, + /// Defines what shadows the constant. + /// + /// Although being ready in the diagnostic, the `PatternMatchingStructFieldVar` option + /// is currently not used. Getting the information about imports and aliases while + /// type checking match branches is too much effort at the moment, compared to gained + /// additional clarity of the error message. We might add support for this option in + /// the future. + shadowing_source: ShadowingSource, name: IdentUnique, constant_span: Span, - constant_decl: Span, + constant_decl_span: Span, is_alias: bool, }, - #[error("Constants cannot shadow variables. The constant \"{name}\" shadows variable with the same name.")] + #[error("Configurables cannot be shadowed. {shadowing_source} \"{name}\" shadows configurable of the same name.")] + ConfigurablesCannotBeShadowed { + /// Defines what shadows the configurable. + /// + /// Using configurable in pattern matching, expecting to behave same as a constant, + /// will result in [CompileError::ConfigurablesCannotBeMatchedAgainst]. + /// Otherwise, we would end up with a very confusing error message that + /// a configurable cannot be shadowed by a variable. + /// In the, unlikely but equally confusing, case of a struct field pattern variable + /// named same as the configurable we also want to provide a better explanation + /// and `shadowing_source` helps us distinguish that case as well. + shadowing_source: ShadowingSource, + name: IdentUnique, + configurable_span: Span, + }, + #[error("Configurables cannot be matched against. Configurable \"{name}\" cannot be used in pattern matching.")] + ConfigurablesCannotBeMatchedAgainst { + name: IdentUnique, + configurable_span: Span, + }, + #[error( + "Constants cannot shadow variables. Constant \"{name}\" shadows variable of the same name." + )] ConstantShadowsVariable { name: IdentUnique, variable_span: Span, }, - #[error("The imported symbol \"{name}\" shadows another symbol with the same name.")] + #[error("{existing_constant_or_configurable} of the name \"{name}\" already exists.")] + ConstantDuplicatesConstantOrConfigurable { + /// Text "Constant" or "Configurable". Denotes already declared constant or configurable. + existing_constant_or_configurable: &'static str, + /// Text "Constant" or "Configurable". Denotes constant or configurable attempted to be declared. + new_constant_or_configurable: &'static str, + name: IdentUnique, + existing_span: Span, + }, + #[error("Imported symbol \"{name}\" shadows another symbol of the same name.")] ShadowsOtherSymbol { name: IdentUnique }, #[error("The name \"{name}\" is already used for a generic parameter in this scope.")] GenericShadowsGeneric { name: IdentUnique }, @@ -928,7 +967,7 @@ pub enum CompileError { NonStrGenericType { span: Span }, #[error("A contract method cannot call methods belonging to the same ABI")] ContractCallsItsOwnMethod { span: Span }, - #[error("ABI cannot define a method with the same name as its super-ABI \"{superabi}\"")] + #[error("ABI cannot define a method of the same name as its super-ABI \"{superabi}\"")] AbiShadowsSuperAbiMethod { span: Span, superabi: Ident }, #[error("ABI cannot inherit samely named method (\"{method_name}\") from several super-ABIs: \"{superabi1}\" and \"{superabi2}\"")] ConflictingSuperAbiMethods { @@ -1094,7 +1133,10 @@ impl Spanned for CompileError { InvalidOpcodeFromPredicate { span, .. } => span.clone(), ArrayOutOfBounds { span, .. } => span.clone(), ConstantsCannotBeShadowed { name, .. } => name.span(), + ConfigurablesCannotBeShadowed { name, .. } => name.span(), + ConfigurablesCannotBeMatchedAgainst { name, .. } => name.span(), ConstantShadowsVariable { name, .. } => name.span(), + ConstantDuplicatesConstantOrConfigurable { name, .. } => name.span(), ShadowsOtherSymbol { name } => name.span(), GenericShadowsGeneric { name } => name.span(), MatchExpressionNonExhaustive { span, .. } => span.clone(), @@ -1186,28 +1228,31 @@ impl Spanned for CompileError { // - Guide-level explanation: https://github.com/FuelLabs/sway-rfcs/blob/master/rfcs/0011-expressive-diagnostics.md#guide-level-explanation // - Wording guidelines: https://github.com/FuelLabs/sway-rfcs/blob/master/rfcs/0011-expressive-diagnostics.md#wording-guidelines // For concrete examples, look at the existing diagnostics. +// +// The issue and the hints are not displayed if set to `Span::dummy()`. +// +// NOTE: Issue level should actually be the part of the reason. But it would complicate handling of labels in the transitional +// period when we still have "old-style" diagnostics. +// Let's leave it like this. Refactoring currently doesn't pay off. +// And our #[error] macro will anyhow encapsulate it and ensure consistency. impl ToDiagnostic for CompileError { fn to_diagnostic(&self, source_engine: &SourceEngine) -> Diagnostic { let code = Code::semantic_analysis; use CompileError::*; match self { - ConstantsCannotBeShadowed { variable_or_constant, name, constant_span, constant_decl, is_alias } => Diagnostic { + ConstantsCannotBeShadowed { shadowing_source, name, constant_span, constant_decl_span, is_alias } => Diagnostic { reason: Some(Reason::new(code(1), "Constants cannot be shadowed".to_string())), - // NOTE: Issue level should actually be the part of the reason. But it would complicate handling of labels in the transitional - // period when we still have "old-style" diagnostics. - // Let's leave it like this, refactoring at the moment does not pay of. - // And our #[error] macro will anyhow encapsulate it and ensure consistency. issue: Issue::error( source_engine, name.span(), format!( - // Variable "x" shadows constant with the same name + // Variable "x" shadows constant with of same name. // or - // Constant "x" shadows imported constant with the same name + // Constant "x" shadows imported constant of the same name. // or // ... - "{variable_or_constant} \"{name}\" shadows {}constant of the same name.", - if constant_decl.clone() != Span::dummy() { "imported " } else { "" } + "{shadowing_source} \"{name}\" shadows {}constant of the same name.", + if constant_decl_span.clone() != Span::dummy() { "imported " } else { "" } ) ), hints: vec![ @@ -1215,34 +1260,134 @@ impl ToDiagnostic for CompileError { source_engine, constant_span.clone(), format!( - // Constant "x" is declared here. + // Shadowed constant "x" is declared here. // or - // Constant "x" gets imported here. + // Shadowed constant "x" gets imported here. + // or + // ... "Shadowed constant \"{name}\" {} here{}.", - if constant_decl.clone() != Span::dummy() { "gets imported" } else { "is declared" }, + if constant_decl_span.clone() != Span::dummy() { "gets imported" } else { "is declared" }, if *is_alias { " as alias" } else { "" } ) ), - Hint::info( // Ignored if the constant_decl is Span::dummy(). + if matches!(shadowing_source, PatternMatchingStructFieldVar) { + Hint::help( + source_engine, + name.span(), + format!("\"{name}\" is a struct field that defines a pattern variable of the same name.") + ) + } else { + Hint::none() + }, + Hint::info( // Ignored if the `constant_decl_span` is `Span::dummy()`. source_engine, - constant_decl.clone(), + constant_decl_span.clone(), format!("This is the original declaration of the imported constant \"{name}\".") ), ], help: vec![ - format!("Unlike variables, constants cannot be shadowed by other constants or variables."), - match (variable_or_constant.as_str(), constant_decl.clone() != Span::dummy()) { - ("Variable", false) => format!("Consider renaming either the variable \"{name}\" or the constant \"{name}\"."), - ("Constant", false) => "Consider renaming one of the constants.".to_string(), - (variable_or_constant, true) => format!( + "Unlike variables, constants cannot be shadowed by other constants or variables.".to_string(), + match (shadowing_source, *constant_decl_span != Span::dummy()) { + (LetVar | PatternMatchingStructFieldVar, false) => format!("Consider renaming either the {} \"{name}\" or the constant \"{name}\".", + format!("{shadowing_source}").to_lowercase(), + ), + (Const, false) => "Consider renaming one of the constants.".to_string(), + (shadowing_source, true) => format!( "Consider renaming the {} \"{name}\" or using {} for the imported constant.", - variable_or_constant.to_lowercase(), + format!("{shadowing_source}").to_lowercase(), if *is_alias { "a different alias" } else { "an alias" } ), - _ => unreachable!("We can have only the listed combinations: variable/constant shadows a non imported/imported constant.") + }, + if matches!(shadowing_source, PatternMatchingStructFieldVar) { + format!("To rename the pattern variable use the `:`. E.g.: `{name}: some_other_name`.") + } else { + Diagnostic::help_none() + } + ], + }, + ConfigurablesCannotBeShadowed { shadowing_source, name, configurable_span } => Diagnostic { + reason: Some(Reason::new(code(1), "Configurables cannot be shadowed".to_string())), + issue: Issue::error( + source_engine, + name.span(), + format!("{shadowing_source} \"{name}\" shadows configurable of the same name.") + ), + hints: vec![ + Hint::info( + source_engine, + configurable_span.clone(), + format!("Shadowed configurable \"{name}\" is declared here.") + ), + if matches!(shadowing_source, PatternMatchingStructFieldVar) { + Hint::help( + source_engine, + name.span(), + format!("\"{name}\" is a struct field that defines a pattern variable of the same name.") + ) + } else { + Hint::none() + }, + ], + help: vec![ + "Unlike variables, configurables cannot be shadowed by constants or variables.".to_string(), + format!( + "Consider renaming either the {} \"{name}\" or the configurable \"{name}\".", + format!("{shadowing_source}").to_lowercase() + ), + if matches!(shadowing_source, PatternMatchingStructFieldVar) { + format!("To rename the pattern variable use the `:`. E.g.: `{name}: some_other_name`.") + } else { + Diagnostic::help_none() } ], }, + ConfigurablesCannotBeMatchedAgainst { name, configurable_span } => Diagnostic { + reason: Some(Reason::new(code(1), "Configurables cannot be matched against".to_string())), + issue: Issue::error( + source_engine, + name.span(), + format!("\"{name}\" is a configurable and configurables cannot be matched against.") + ), + hints: { + let mut hints = vec![ + Hint::info( + source_engine, + configurable_span.clone(), + format!("Configurable \"{name}\" is declared here.") + ), + ]; + + hints.append(&mut Hint::multi_help(source_engine, &name.span(), vec![ + format!("Are you trying to define a pattern variable named \"{name}\"?"), + format!("In that case, use some other name for the pattern variable,"), + format!("or consider renaming the configurable \"{name}\"."), + ])); + + hints + }, + help: vec![ + "Unlike constants, configurables cannot be matched against in pattern matching.".to_string(), + "That's not possible, because patterns to match against must be compile-time constants.".to_string(), + "Configurables are run-time constants. Their values are defined during the deployment.".to_string(), + Diagnostic::help_empty_line(), + "To test against a configurable, consider:".to_string(), + format!("{}- replacing the `match` expression with `if-else`s altogether.", Indent::Single), + format!("{}- matching against a variable and comparing that variable afterwards with the configurable.", Indent::Single), + format!("{} E.g., instead of:", Indent::Single), + Diagnostic::help_empty_line(), + format!("{} SomeStruct {{ x: A_CONFIGURABLE, y: 42 }} => {{", Indent::Double), + format!("{} do_something();", Indent::Double), + format!("{} }}", Indent::Double), + Diagnostic::help_empty_line(), + format!("{} to have:", Indent::Single), + Diagnostic::help_empty_line(), + format!("{} SomeStruct {{ x, y: 42 }} => {{", Indent::Double), + format!("{} if x == A_CONFIGURABLE {{", Indent::Double), + format!("{} do_something();", Indent::Double), + format!("{} }}", Indent::Double), + format!("{} }}", Indent::Double), + ], + }, ConstantShadowsVariable { name , variable_span } => Diagnostic { reason: Some(Reason::new(code(1), "Constants cannot shadow variables".to_string())), issue: Issue::error( @@ -1262,6 +1407,41 @@ impl ToDiagnostic for CompileError { format!("Consider renaming either the variable or the constant."), ], }, + ConstantDuplicatesConstantOrConfigurable { existing_constant_or_configurable, new_constant_or_configurable, name, existing_span } => Diagnostic { + reason: Some(Reason::new(code(1), match (*existing_constant_or_configurable, *new_constant_or_configurable) { + ("Constant", "Constant") => "Constant of the same name already exists".to_string(), + ("Constant", "Configurable") => "Constant of the same name as configurable already exists".to_string(), + ("Configurable", "Constant") => "Configurable of the same name as constant already exists".to_string(), + _ => unreachable!("We can have only the listed combinations. Configurable duplicating configurable is not a valid combination.") + })), + issue: Issue::error( + source_engine, + name.span(), + format!("{new_constant_or_configurable} \"{name}\" has the same name as an already declared {}.", + existing_constant_or_configurable.to_lowercase() + ) + ), + hints: vec![ + Hint::info( + source_engine, + existing_span.clone(), + format!("{existing_constant_or_configurable} \"{name}\" is {}declared here.", + // If a constant clashes with an already declared constant. + if existing_constant_or_configurable == new_constant_or_configurable { + "already " + } else { + "" + } + ) + ), + ], + help: vec![ + match (*existing_constant_or_configurable, *new_constant_or_configurable) { + ("Constant", "Constant") => "Consider renaming one of the constants, or in case of imported constants, using an alias.".to_string(), + _ => "Consider renaming either the configurable or the constant, or in case of an imported constant, using an alias.".to_string(), + }, + ], + }, MultipleDefinitionsOfMatchArmVariable { match_value, match_type, first_definition, first_definition_is_struct_field, duplicate, duplicate_is_struct_field } => Diagnostic { reason: Some(Reason::new(code(1), "Match pattern variable is already defined".to_string())), issue: Issue::error( @@ -2513,9 +2693,31 @@ pub enum InvalidImplementingForType { impl fmt::Display for InvalidImplementingForType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - InvalidImplementingForType::SelfType => f.write_str("\"Self\""), - InvalidImplementingForType::Placeholder => f.write_str("Placeholder `_`"), - InvalidImplementingForType::Other => f.write_str("This"), + Self::SelfType => f.write_str("\"Self\""), + Self::Placeholder => f.write_str("Placeholder `_`"), + Self::Other => f.write_str("This"), + } + } +} + +/// Defines what shadows a constant or a configurable. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum ShadowingSource { + /// A constant or a configurable is shadowed by a constant. + Const, + /// A constant or a configurable is shadowed by a local variable declared with the `let` keyword. + LetVar, + /// A constant or a configurable is shadowed by a variable declared in pattern matching, + /// being a struct field. E.g., `S { some_field }`. + PatternMatchingStructFieldVar, +} + +impl fmt::Display for ShadowingSource { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::Const => f.write_str("Constant"), + Self::LetVar => f.write_str("Variable"), + Self::PatternMatchingStructFieldVar => f.write_str("Pattern variable"), } } } diff --git a/sway-lsp/benches/lsp_benchmarks/compile.rs b/sway-lsp/benches/lsp_benchmarks/compile.rs index 6916582e271..fdab8f01094 100644 --- a/sway-lsp/benches/lsp_benchmarks/compile.rs +++ b/sway-lsp/benches/lsp_benchmarks/compile.rs @@ -1,27 +1,36 @@ use criterion::{black_box, criterion_group, Criterion}; -use lsp_types::Url; use std::sync::Arc; use sway_core::{Engines, ExperimentalFlags}; use sway_lsp::core::session; +use tokio::runtime::Runtime; const NUM_DID_CHANGE_ITERATIONS: usize = 10; fn benchmarks(c: &mut Criterion) { - let experimental = ExperimentalFlags { - new_encoding: false, - }; + let (uri, session, _) = Runtime::new() + .unwrap() + .block_on(async { black_box(super::compile_test_project().await) }); + + let build_plan = session + .build_plan_cache + .get_or_update(&session.sync.manifest_path(), || session::build_plan(&uri)) + .unwrap(); - // Load the test project - let uri = Url::from_file_path(super::benchmark_dir().join("src/main.sw")).unwrap(); let mut lsp_mode = Some(sway_core::LspConfig { optimized_build: false, file_versions: Default::default(), }); + + let experimental = ExperimentalFlags { + new_encoding: false, + }; + c.bench_function("compile", |b| { b.iter(|| { let engines = Engines::default(); let _ = black_box( - session::compile(&uri, &engines, None, lsp_mode.clone(), experimental).unwrap(), + session::compile(&build_plan, &engines, None, lsp_mode.clone(), experimental) + .unwrap(), ); }) }); @@ -29,7 +38,7 @@ fn benchmarks(c: &mut Criterion) { c.bench_function("traverse", |b| { let engines = Engines::default(); let results = black_box( - session::compile(&uri, &engines, None, lsp_mode.clone(), experimental).unwrap(), + session::compile(&build_plan, &engines, None, lsp_mode.clone(), experimental).unwrap(), ); let session = Arc::new(session::Session::new()); b.iter(|| { @@ -44,7 +53,8 @@ fn benchmarks(c: &mut Criterion) { b.iter(|| { for _ in 0..NUM_DID_CHANGE_ITERATIONS { let _ = black_box( - session::compile(&uri, &engines, None, lsp_mode.clone(), experimental).unwrap(), + session::compile(&build_plan, &engines, None, lsp_mode.clone(), experimental) + .unwrap(), ); } }) diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index e0fe109c43a..6dab2952254 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -29,6 +29,7 @@ use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use std::{ path::PathBuf, sync::{atomic::AtomicBool, Arc}, + time::SystemTime, }; use sway_core::{ decl_engine::DeclEngine, @@ -61,6 +62,7 @@ pub struct CompiledProgram { pub struct Session { token_map: TokenMap, pub runnables: RunnableMap, + pub build_plan_cache: BuildPlanCache, pub compiled_program: RwLock, pub engines: RwLock, pub sync: SyncWorkspace, @@ -80,6 +82,7 @@ impl Session { Session { token_map: TokenMap::new(), runnables: DashMap::new(), + build_plan_cache: BuildPlanCache::default(), metrics: DashMap::new(), compiled_program: RwLock::new(CompiledProgram::default()), engines: <_>::default(), @@ -228,7 +231,7 @@ impl Session { } /// Create a [BuildPlan] from the given [Url] appropriate for the language server. -pub(crate) fn build_plan(uri: &Url) -> Result { +pub fn build_plan(uri: &Url) -> Result { let _p = tracing::trace_span!("build_plan").entered(); let manifest_dir = PathBuf::from(uri.path()); let manifest = @@ -254,17 +257,16 @@ pub(crate) fn build_plan(uri: &Url) -> Result { } pub fn compile( - uri: &Url, + build_plan: &BuildPlan, engines: &Engines, retrigger_compilation: Option>, lsp_mode: Option, experimental: sway_core::ExperimentalFlags, ) -> Result, Handler)>, LanguageServerError> { let _p = tracing::trace_span!("compile").entered(); - let build_plan = build_plan(uri)?; let tests_enabled = true; pkg::check( - &build_plan, + build_plan, BuildTarget::default(), true, lsp_mode, @@ -382,8 +384,11 @@ pub fn parse_project( experimental: sway_core::ExperimentalFlags, ) -> Result<(), LanguageServerError> { let _p = tracing::trace_span!("parse_project").entered(); + let build_plan = session + .build_plan_cache + .get_or_update(&session.sync.manifest_path(), || build_plan(uri))?; let results = compile( - uri, + &build_plan, engines, retrigger_compilation, lsp_mode.clone(), @@ -508,6 +513,56 @@ pub(crate) fn program_id_from_path( Ok(program_id) } +/// A cache for storing and retrieving BuildPlan objects. +#[derive(Debug, Clone)] +pub struct BuildPlanCache { + /// The cached BuildPlan and its last update time + cache: Arc>>, +} + +impl Default for BuildPlanCache { + fn default() -> Self { + Self { + cache: Arc::new(RwLock::new(None)), + } + } +} + +impl BuildPlanCache { + /// Retrieves a BuildPlan from the cache or updates it if necessary. + pub fn get_or_update( + &self, + manifest_path: &Option, + update_fn: F, + ) -> Result + where + F: FnOnce() -> Result, + { + let should_update = { + let cache = self.cache.read(); + manifest_path + .as_ref() + .and_then(|path| path.metadata().ok()?.modified().ok()) + .map_or(cache.is_none(), |time| { + cache.as_ref().map_or(true, |&(_, last)| time > last) + }) + }; + + if should_update { + let new_plan = update_fn()?; + let mut cache = self.cache.write(); + *cache = Some((new_plan.clone(), SystemTime::now())); + Ok(new_plan) + } else { + let cache = self.cache.read(); + cache + .as_ref() + .map(|(plan, _)| plan.clone()) + .ok_or(LanguageServerError::BuildPlanCacheIsEmpty) + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/sway-lsp/src/core/sync.rs b/sway-lsp/src/core/sync.rs index bf6c9fa73a7..f00189880fe 100644 --- a/sway-lsp/src/core/sync.rs +++ b/sway-lsp/src/core/sync.rs @@ -175,7 +175,7 @@ impl SyncWorkspace { .ok() } - pub(crate) fn manifest_path(&self) -> Option { + pub fn manifest_path(&self) -> Option { self.manifest_dir() .map(|dir| dir.join(sway_utils::constants::MANIFEST_FILE_NAME)) .ok() diff --git a/sway-lsp/src/error.rs b/sway-lsp/src/error.rs index 740a1127d46..e11fd90d129 100644 --- a/sway-lsp/src/error.rs +++ b/sway-lsp/src/error.rs @@ -14,6 +14,8 @@ pub enum LanguageServerError { // Top level errors #[error("Failed to create build plan. {0}")] BuildPlanFailed(anyhow::Error), + #[error("Build Plan Cache is empty")] + BuildPlanCacheIsEmpty, #[error("Failed to compile. {0}")] FailedToCompile(anyhow::Error), #[error("Failed to parse document")] diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index 58003027f20..acfa4bf9de2 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -113,7 +113,7 @@ impl Parse for ty::TySideEffect { if let Some(span) = ctx .namespace .submodule(ctx.engines, mod_path) - .and_then(|tgt_submod| tgt_submod.span.clone()) + .and_then(|tgt_submod| tgt_submod.span().clone()) { token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); } @@ -169,7 +169,7 @@ impl Parse for ty::TySideEffect { if let Some(span) = ctx .namespace .submodule(ctx.engines, call_path) - .and_then(|tgt_submod| tgt_submod.span.clone()) + .and_then(|tgt_submod| tgt_submod.span().clone()) { token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); } @@ -192,7 +192,7 @@ impl Parse for ty::TySideEffect { if let Some(span) = ctx .namespace .submodule(ctx.engines, &[mod_name.clone()]) - .and_then(|tgt_submod| tgt_submod.span.clone()) + .and_then(|tgt_submod| tgt_submod.span().clone()) { token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); } @@ -981,8 +981,7 @@ impl Parse for ty::TyIntrinsicFunctionKind { impl Parse for ty::TyScrutinee { fn parse(&self, ctx: &ParseContext) { use ty::TyScrutineeVariant::{ - CatchAll, Configurable, Constant, EnumScrutinee, Literal, Or, StructScrutinee, Tuple, - Variable, + CatchAll, Constant, EnumScrutinee, Literal, Or, StructScrutinee, Tuple, Variable, }; match &self.variant { CatchAll => {} @@ -992,12 +991,6 @@ impl Parse for ty::TyScrutinee { token.type_def = Some(TypeDefinition::Ident(decl.call_path.suffix.clone())); } } - Configurable(name, _, decl) => { - if let Some(mut token) = ctx.tokens.try_get_mut_with_retry(&ctx.ident(name)) { - token.typed = Some(TypedAstToken::TypedScrutinee(self.clone())); - token.type_def = Some(TypeDefinition::Ident(decl.call_path.suffix.clone())); - } - } Literal(_) => { if let Some(mut token) = ctx .tokens @@ -1209,7 +1202,7 @@ fn collect_call_path_prefixes(ctx: &ParseContext, prefixes: &[Ident]) { if let Some(span) = ctx .namespace .submodule(ctx.engines, mod_path) - .and_then(|tgt_submod| tgt_submod.span.clone()) + .and_then(|tgt_submod| tgt_submod.span().clone()) { token.kind = SymbolKind::Module; token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/deduplication_of_shadowing_errors/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/deduplication_of_shadowing_errors/test.toml index 895e150b749..968be6793f5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/deduplication_of_shadowing_errors/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/deduplication_of_shadowing_errors/test.toml @@ -3,12 +3,12 @@ category = "fail" #check: $()error #nextln: $()main.sw:7 #check: $()use lib::Struct; -#check: $()The imported symbol "Struct" shadows another symbol with the same name. +#check: $()Imported symbol "Struct" shadows another symbol of the same name. #check: $()error #nextln: $()main.sw:8 #check: $()use lib::Struct; -#check: $()The imported symbol "Struct" shadows another symbol with the same name. +#check: $()Imported symbol "Struct" shadows another symbol of the same name. #check: $()Constants cannot be shadowed #nextln: $()main.sw:13 diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/test.toml index 304d05109d3..34426f29662 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/test.toml @@ -2,30 +2,30 @@ category = "fail" #check: $()error #check: $()use ::lib_1_2::Items1_Struct; -#nextln: $()The imported symbol "Items1_Struct" shadows another symbol with the same name. +#nextln: $()Imported symbol "Items1_Struct" shadows another symbol of the same name. #check: $()error #check: $()use ::lib_1_2::Items1_Enum; -#nextln: $()The imported symbol "Items1_Enum" shadows another symbol with the same name. +#nextln: $()Imported symbol "Items1_Enum" shadows another symbol of the same name. #check: $()error #check: $()use ::lib_1_2::Items1_Variants::X; -#nextln: $()The imported symbol "X" shadows another symbol with the same name. +#nextln: $()Imported symbol "X" shadows another symbol of the same name. #check: $()error #check: $()use ::lib_1_2::Items1_Variants::Y; -#nextln: $()The imported symbol "Y" shadows another symbol with the same name. +#nextln: $()Imported symbol "Y" shadows another symbol of the same name. #check: $()error #check: $()use ::lib_1_2::ITEMS_1_FUNCTION_RES; -#nextln: $()The imported symbol "ITEMS_1_FUNCTION_RES" shadows another symbol with the same name. +#nextln: $()Imported symbol "ITEMS_1_FUNCTION_RES" shadows another symbol of the same name. #check: $()error #check: $()use ::lib_1_2::items_1_function; -#nextln: $()The imported symbol "items_1_function" shadows another symbol with the same name. +#nextln: $()Imported symbol "items_1_function" shadows another symbol of the same name. #check: $()error #check: $()use ::lib_1_2::Items1Trait; -#nextln: $()The imported symbol "Items1Trait" shadows another symbol with the same name. +#nextln: $()Imported symbol "Items1Trait" shadows another symbol of the same name. #check: $()Aborting due to 7 errors. diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadow_import/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/shadow_import/test.toml index 0370f2374de..3d004670c3c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/shadow_import/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadow_import/test.toml @@ -1,4 +1,4 @@ category = "fail" -# check: $()The imported symbol "Foo" shadows another symbol with the same name. -# check: $()The imported symbol "Bar2" shadows another symbol with the same name. +# check: $()Imported symbol "Foo" shadows another symbol of the same name. +# check: $()Imported symbol "Bar2" shadows another symbol of the same name. diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/Forc.lock new file mode 100644 index 00000000000..f1e5fe7934c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-64A912F71AFE52EA" + +[[package]] +name = "shadowed_configurables" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/Forc.toml new file mode 100644 index 00000000000..1cbcb5f14b7 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +implicit-std = false +license = "Apache-2.0" +name = "shadowed_configurables" + +[dependencies] +core = { path = "../../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/src/lib.sw new file mode 100644 index 00000000000..1b41f86d27d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/src/lib.sw @@ -0,0 +1,7 @@ +library; + +pub const LIB_X = 5; + +pub const LIB_Y = 5; + +pub const LIB_Z = 5; diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/src/main.sw new file mode 100644 index 00000000000..5bca5a5c105 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/src/main.sw @@ -0,0 +1,49 @@ +script; + +mod lib; + +const CONST_A: u8 = 1; + +use lib::LIB_X; + +configurable { + X: u8 = 10, + Y: u8 = 11, + A: u8 = 13, + B: u8 = 14, + CONST_A: u8 = 15, + CONST_B: u8 = 16, + LIB_X: u8 = 17, + LIB_Y: u8 = 18, + LIB_Z_ALIAS: u8 = 19, + LET_A: u8 = 20, + LET_B: u8 = 21, + LET_C: u8 = 22, +} + +const CONST_B: u8 = 2; + +use lib::LIB_Y; + +use lib::LIB_Z as LIB_Z_ALIAS; + +struct S { + x: u8, +} + +enum E { + A: u8, +} + +fn main() { + let X = 101u8; + const Y: u8 = 102; + + { + let A = 103u8; + const B: u8 = 104; + } + + let S { x: LET_A } = S { x: 105 }; + let (_, LET_B) = (106u8, 107u8); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/test.toml new file mode 100644 index 00000000000..a3ef69266b2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables/test.toml @@ -0,0 +1,84 @@ +category = "fail" + +#check: $()error +#sameln: $()Constant of the same name as configurable already exists +#check: $()const CONST_A: u8 = 1; +#nextln: $()Constant "CONST_A" is declared here. +#check: $()CONST_A: u8 = 15, +#nextln: $()Configurable "CONST_A" has the same name as an already declared constant. + +#check: $()error +#sameln: $()Constant of the same name as configurable already exists +#check: $()use lib::LIB_X; +#nextln: $()Constant "LIB_X" is declared here. +#check: $()LIB_X: u8 = 17, +#nextln: $()Configurable "LIB_X" has the same name as an already declared constant. + +#check: $()error +#sameln: $()Constant of the same name as configurable already exists +#check: $()LIB_Y: u8 = 18, +#nextln: $()Configurable "LIB_Y" has the same name as an already declared constant. +#check: $()use lib::LIB_Y; +#nextln: $()Constant "LIB_Y" is declared here. + +#check: $()error +#sameln: $()Constant of the same name as configurable already exists +#check: $()LIB_Z_ALIAS: u8 = 19, +#nextln: $()Configurable "LIB_Z_ALIAS" has the same name as an already declared constant. +#check: $()use lib::LIB_Z as LIB_Z_ALIAS; +#nextln: $()Constant "LIB_Z_ALIAS" is declared here. + +#check: $()error +#sameln: $()Configurable of the same name as constant already exists +#check: $()CONST_B: u8 = 16, +#nextln: $()Configurable "CONST_B" is declared here. +#check: $()const CONST_B: u8 = 2; +#nextln: $()Constant "CONST_B" has the same name as an already declared configurable. + +#check: $()error +#sameln: $()Configurables cannot be shadowed +#check: $()X: u8 = 10, +#nextln: $()Shadowed configurable "X" is declared here. +#check: $()let X = 101u8; +#nextln: $()Variable "X" shadows configurable of the same name. +#check: $()Consider renaming either the variable "X" or the configurable "X". + +#check: $()error +#sameln: $()Configurables cannot be shadowed +#check: $()Y: u8 = 11, +#nextln: $()Shadowed configurable "Y" is declared here. +#check: $()const Y: u8 = 102; +#nextln: $()Constant "Y" shadows configurable of the same name. +#check: $()Consider renaming either the constant "Y" or the configurable "Y". + +#check: $()error +#sameln: $()Configurables cannot be shadowed +#check: $()A: u8 = 13, +#nextln: $()Shadowed configurable "A" is declared here. +#check: $()let A = 103u8; +#nextln: $()Variable "A" shadows configurable of the same name. +#check: $()Consider renaming either the variable "A" or the configurable "A". + +#check: $()error +#sameln: $()Configurables cannot be shadowed +#check: $()B: u8 = 14, +#nextln: $()Shadowed configurable "B" is declared here. +#check: $()const B: u8 = 104; +#nextln: $()Constant "B" shadows configurable of the same name. +#check: $()Consider renaming either the constant "B" or the configurable "B". + +#check: $()error +#sameln: $()Configurables cannot be shadowed +#check: $()LET_A: u8 = 20, +#nextln: $()Shadowed configurable "LET_A" is declared here. +#check: $()let S { x: LET_A } = S { x: 105 }; +#nextln: $()Variable "LET_A" shadows configurable of the same name. +#check: $()Consider renaming either the variable "LET_A" or the configurable "LET_A". + +#check: $()error +#sameln: $()Configurables cannot be shadowed +#check: $()LET_B: u8 = 21, +#nextln: $()Shadowed configurable "LET_B" is declared here. +#check: $()let (_, LET_B) = (106u8, 107u8); +#nextln: $()Variable "LET_B" shadows configurable of the same name. +#check: $()Consider renaming either the variable "LET_B" or the configurable "LET_B". diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/Forc.lock new file mode 100644 index 00000000000..ed28297caaf --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-8D5D4F6C9D8606CC" + +[[package]] +name = "shadowed_configurables_in_pattern_matching" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/Forc.toml new file mode 100644 index 00000000000..82f3d90af2d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +implicit-std = false +license = "Apache-2.0" +name = "shadowed_configurables_in_pattern_matching" + +[dependencies] +core = { path = "../../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/src/main.sw new file mode 100644 index 00000000000..f6d669db681 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/src/main.sw @@ -0,0 +1,50 @@ +script; + +enum E { + V: (u8, u8, u8), +} + +struct S { + x: u8, + y: u8, + z: u8, +} + +struct SConfig { + CONFIG: u8, +} + +configurable { + X: u8 = 10, + Y: u8 = 11, + Z: u8 = 12, + CONFIG: u8 = 13, +} + +fn main() { + let _ = match 42 { + X => 101, + }; + + let e = E::V((100, 100, 100)); + let _ = match e { + E::V((_, X, _)) => 101, + E::V((X, Y, Z)) => 102, + E::V((X, _, _)) | E::V((_, _, X)) => 103, + }; + + let s = S { x: 100, y: 100, z: 100 }; + let _ = match s { + S { x: X, .. } => 101, + S { y: X, .. } => 102, + S { x: X, y: Y, z: Z } => 103, + S { x: X, .. } | S { z: X, .. } => 104, + }; + + let s = SConfig { CONFIG: 100 }; + let _ = match s { + SConfig { CONFIG } => 101, + SConfig { CONFIG: CONFIG } => 102, + SConfig { CONFIG: CONFIG } | SConfig { CONFIG } => 103, + }; +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/test.toml new file mode 100644 index 00000000000..a9ea6d12ce2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_configurables_in_pattern_matching/test.toml @@ -0,0 +1,149 @@ +category = "fail" + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()X: u8 = 10, +#nextln: $()Configurable "X" is declared here. +#check: $()X => 101, +#nextln: $()"X" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "X"? +#check: $()or consider renaming the configurable "X". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()X: u8 = 10, +#nextln: $()Configurable "X" is declared here. +#check: $()E::V((_, X, _)) => 101, +#nextln: $()"X" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "X"? +#check: $()or consider renaming the configurable "X". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()X: u8 = 10, +#nextln: $()Configurable "X" is declared here. +#check: $()E::V((X, Y, Z)) => 102, +#nextln: $()"X" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "X"? +#check: $()or consider renaming the configurable "X". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()Y: u8 = 11, +#nextln: $()Configurable "Y" is declared here. +#check: $()E::V((X, Y, Z)) => 102, +#nextln: $()"Y" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "Y"? +#check: $()or consider renaming the configurable "Y". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()Z: u8 = 12, +#nextln: $()Configurable "Z" is declared here. +#check: $()E::V((X, Y, Z)) => 102, +#nextln: $()"Z" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "Z"? +#check: $()or consider renaming the configurable "Z". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()X: u8 = 10, +#nextln: $()Configurable "X" is declared here. +#check: $()E::V((X, _, _)) | E::V((_, _, X)) => 103, +#nextln: $()"X" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "X"? +#check: $()or consider renaming the configurable "X". + +#not: $()E::V((X, _, _)) | E::V((_, _, X)) => 101, + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()X: u8 = 10, +#nextln: $()Configurable "X" is declared here. +#check: $()S { x: X, .. } => 101, +#nextln: $()"X" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "X"? +#check: $()or consider renaming the configurable "X". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()X: u8 = 10, +#nextln: $()Configurable "X" is declared here. +#check: $()S { y: X, .. } => 102, +#nextln: $()"X" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "X"? +#check: $()or consider renaming the configurable "X". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()X: u8 = 10, +#nextln: $()Configurable "X" is declared here. +#check: $()S { x: X, y: Y, z: Z } => 103, +#nextln: $()"X" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "X"? +#check: $()or consider renaming the configurable "X". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()Y: u8 = 11, +#nextln: $()Configurable "Y" is declared here. +#check: $()S { x: X, y: Y, z: Z } => 103, +#nextln: $()"Y" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "Y"? +#check: $()or consider renaming the configurable "Y". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()Z: u8 = 12, +#nextln: $()Configurable "Z" is declared here. +#check: $()S { x: X, y: Y, z: Z } => 103, +#nextln: $()"Z" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "Z"? +#check: $()or consider renaming the configurable "Z". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()X: u8 = 10, +#nextln: $()Configurable "X" is declared here. +#check: $()S { x: X, .. } | S { z: X, .. } => 104, +#nextln: $()"X" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "X"? +#check: $()or consider renaming the configurable "X". + +#not: $()S { x: X, .. } | S { z: X, .. } => 104, + +#check: $()error +#sameln: $()Configurables cannot be shadowed +#check: $()CONFIG: u8 = 13, +#nextln: $()Shadowed configurable "CONFIG" is declared here. +#check: $()SConfig { CONFIG } => 101, +#nextln: $()Pattern variable "CONFIG" shadows configurable of the same name. +#nextln: $()"CONFIG" is a struct field that defines a pattern variable of the same name. +#check: $()To rename the pattern variable use the `:`. E.g.: `CONFIG: some_other_name`. + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()CONFIG: u8 = 13, +#nextln: $()Configurable "CONFIG" is declared here. +#check: $()SConfig { CONFIG: CONFIG } => 102, +#nextln: $()"CONFIG" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "CONFIG"? +#check: $()or consider renaming the configurable "CONFIG". + +#check: $()error +#sameln: $()Configurables cannot be matched against +#check: $()CONFIG: u8 = 13, +#nextln: $()Configurable "CONFIG" is declared here. +#check: $()SConfig { CONFIG: CONFIG } | SConfig { CONFIG } => 103, +#nextln: $()"CONFIG" is a configurable and configurables cannot be matched against. +#nextln: $()Are you trying to define a pattern variable named "CONFIG"? +#check: $()or consider renaming the configurable "CONFIG". + +#check: $()error +#sameln: $()Configurables cannot be shadowed +#check: $()CONFIG: u8 = 13, +#nextln: $()Shadowed configurable "CONFIG" is declared here. +#check: $()SConfig { CONFIG: CONFIG } | SConfig { CONFIG } => 103, +#nextln: $()Pattern variable "CONFIG" shadows configurable of the same name. +#nextln: $()"CONFIG" is a struct field that defines a pattern variable of the same name. +#check: $()To rename the pattern variable use the `:`. E.g.: `CONFIG: some_other_name`. diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars/src/main.sw index 3af2f1d8970..1e0589c8a72 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars/src/main.sw @@ -21,6 +21,14 @@ const M_Z = 41; use lib::L_Y; use lib::L_Z; +use lib::L_Z as L_Z_ALIAS; + +struct StructWithConstNames { + M_X: u64, + L_Y: u64, + L_Z_ALIAS: u64, +} + fn main() { // local const shadowing a module const const M_Y = 5; @@ -96,6 +104,19 @@ fn main() { // const shadowing a locally imported const use lib::L_M; const L_M = 15; + + let s = StructWithConstNames { + M_X, + L_Y, + L_Z_ALIAS, + }; + + // pattern variables shadowing different types of consts + let _ = match s { + StructWithConstNames { M_X, L_Y, L_Z_ALIAS } => { + 42 + }, + }; } use lib::L_N; diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars/test.toml index d85b81a3f8d..ed23a889182 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars/test.toml @@ -1,51 +1,49 @@ category = "fail" #check: $()error - #check: $()use lib::L_A; #nextln: $()use lib::L_A; -#nextln: $()The imported symbol "L_A" shadows another symbol with the same name. +#nextln: $()Imported symbol "L_A" shadows another symbol of the same name. +#check: $()error +#sameln: $()Constant of the same name already exists +#check: $()use lib::L_X; +#nextln: $()Constant "L_X" is already declared here. #check: $()const L_X = 1; -#nextln: $()Constant "L_X" was already defined in scope. +#nextln: $()Constant "L_X" has the same name as an already declared constant. +#check: $()error +#sameln: $()Constant of the same name already exists #check: $()const M_X = 2; +#nextln: $()Constant "M_X" is already declared here. #nextln: $()const M_X = 3; -#nextln: $()Constant "M_X" was already defined in scope. +#nextln: $()Constant "M_X" has the same name as an already declared constant. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const M_Y = 4; #nextln: $()Shadowed constant "M_Y" is declared here. - #check: $()const M_Y = 5; #nextln: $()Constant "M_Y" shadows constant of the same name. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const M_Y = 5; #nextln: $()Shadowed constant "M_Y" is declared here. - #check: $()const M_Y = 55; #nextln: $()Constant "M_Y" shadows constant of the same name. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()use lib::L_Y; #nextln: $()Shadowed constant "L_Y" gets imported here. - #check: $()const L_Y = 6; #nextln: $()Constant "L_Y" shadows imported constant of the same name. - #check: $()pub const L_Y = 5; #nextln: $()This is the original declaration of the imported constant "L_Y". #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const F_X = 7; #nextln: $()Shadowed constant "F_X" is declared here. #nextln: $()const F_X = 8; @@ -53,7 +51,6 @@ category = "fail" #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const F_X = 8; #nextln: $()Shadowed constant "F_X" is declared here. #check: $()const F_X = 81; @@ -61,37 +58,29 @@ category = "fail" #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const F_Y = 9; #nextln: $()Shadowed constant "F_Y" is declared here. - #check: $()const F_Y = 10; #nextln: $()Constant "F_Y" shadows constant of the same name. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const L_X = 1; #nextln: $()Shadowed constant "L_X" is declared here. - #check: $()let L_X = 100; #nextln: $()Variable "L_X" shadows constant of the same name. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()use lib::L_X; #nextln: $()Shadowed constant "L_X" gets imported here. - #check: $()let L_X = 100; #nextln: $()Variable "L_X" shadows imported constant of the same name. - #check: $()pub const L_X = 5; #nextln: $()This is the original declaration of the imported constant "L_X". #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const F_Z = 11; #nextln: $()Shadowed constant "F_Z" is declared here. #nextln: $()let F_Z = 102; @@ -99,7 +88,6 @@ category = "fail" #check: $()error #sameln: $()Constants cannot shadow variables - #check: $()let F_A = 103; #nextln: $()This is the shadowed variable "F_A". #nextln: $()const F_A = 12; @@ -107,108 +95,136 @@ category = "fail" #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const M_Y = 5; #nextln: $()Shadowed constant "M_Y" is declared here. - #check: $()let M_Y = 106; #nextln: $()Variable "M_Y" shadows constant of the same name. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const M_Z = 41; #nextln: $()Shadowed constant "M_Z" is declared here. - #check: $()let M_Z = 107; #nextln: $()Variable "M_Z" shadows constant of the same name. #check: $()error #sameln: $()Constants cannot shadow variables - #check: $()let B = 108; #nextln: $()This is the shadowed variable "B". - #check: $()const B = 13; #nextln: $()Constant "B" shadows variable of the same name. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const F_K = 14; #nextln: $()Shadowed constant "F_K" is declared here. - #check: $()let F_K = 109; #nextln: $()Variable "F_K" shadows constant of the same name. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()use lib::L_Z; #nextln: $()Shadowed constant "L_Z" gets imported here. - #check: $()let L_Z = 110; #nextln: $()Variable "L_Z" shadows imported constant of the same name. - #check: $()pub const L_Z = 5; #nextln: $()This is the original declaration of the imported constant "L_Z". #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()use lib::L_K; #nextln: $()Shadowed constant "L_K" gets imported here. - #check: $()let L_K = 111; #nextln: $()Variable "L_K" shadows imported constant of the same name. - #check: $()pub const L_K = 5; #nextln: $()This is the original declaration of the imported constant "L_K". #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()use lib::L_M; #nextln: $()Shadowed constant "L_M" gets imported here. - #check: $()const L_M = 15; #nextln: $()Constant "L_M" shadows imported constant of the same name. - #check: $()pub const L_M = 5; #nextln: $()This is the original declaration of the imported constant "L_M". +#check: $()error +#sameln: $()Constants cannot be shadowed +#check: $()const M_X = 3; +#nextln: $()Shadowed constant "M_X" is declared here. +#check: $()StructWithConstNames { M_X, L_Y, L_Z_ALIAS } => { +#nextln: $()Variable "M_X" shadows constant of the same name. + +#check: $()error +#sameln: $()Constants cannot be shadowed +#check: $()use lib::L_Y; +#nextln: $()Shadowed constant "L_Y" gets imported here. +#check: $()StructWithConstNames { M_X, L_Y, L_Z_ALIAS } => { +#nextln: $()Variable "L_Y" shadows imported constant of the same name. +#check: $()pub const L_Y = 5; +#nextln: $()This is the original declaration of the imported constant "L_Y". + +#check: $()error +#sameln: $()Constants cannot be shadowed +#check: $()use lib::L_Z as L_Z_ALIAS; +#nextln: $()Shadowed constant "L_Z_ALIAS" gets imported here as alias. +#check: $()StructWithConstNames { M_X, L_Y, L_Z_ALIAS } => { +#nextln: $()Variable "L_Z_ALIAS" shadows imported constant of the same name. +#check: $()pub const L_Z = 5; +#nextln: $()This is the original declaration of the imported constant "L_Z_ALIAS". + +#check: $()error +#sameln: $()Constant of the same name already exists +#check: $()const S_X = 200; +#nextln: $()Constant "S_X" is already declared here. #check: $()const S_X = 201; -#nextln: $()Constant "S_X" was already defined in scope. +#nextln: $()Constant "S_X" has the same name as an already declared constant. +#check: $()error +#sameln: $()Constant of the same name already exists +#check: $()use lib::L_N; +#nextln: $()Constant "L_N" is already declared here. #check: $()const L_N = 202; -#check: $()Constant "L_N" was already defined in scope. +#nextln: $()Constant "L_N" has the same name as an already declared constant. +#check: $()error +#sameln: $()Constant of the same name already exists +#check: $()const M_M = 16; +#nextln: $()Constant "M_M" is already declared here. #check: $()const M_M = 203; -#check: $()Constant "M_M" was already defined in scope. +#nextln: $()Constant "M_M" has the same name as an already declared constant. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const S_Y = 204; #nextln: $()Shadowed constant "S_Y" is declared here. - #check: $()const S_Y = 205; #nextln: $()Constant "S_Y" shadows constant of the same name. +#check: $()error +#sameln: $()Constant of the same name already exists +#check: $()const E_X = 300; +#nextln: $()Constant "E_X" is already declared here. #check: $()const E_X = 301; -#nextln: $()Constant "E_X" was already defined in scope. +#nextln: $()Constant "E_X" has the same name as an already declared constant. +#check: $()error +#sameln: $()Constant of the same name already exists +#check: $()use lib::L_N; +#nextln: $()Constant "L_N" is already declared here. #check: $()const L_N = 302; -#check: $()Constant "L_N" was already defined in scope. +#nextln: $()Constant "L_N" has the same name as an already declared constant. +#check: $()error +#sameln: $()Constant of the same name already exists +#check: $()const M_M = 16; +#nextln: $()Constant "M_M" is already declared here. #check: $()const M_M = 303; -#check: $()Constant "M_M" was already defined in scope. +#nextln: $()Constant "M_M" has the same name as an already declared constant. #check: $()error #sameln: $()Constants cannot be shadowed - #check: $()const E_Y = 304; #nextln: $()Shadowed constant "E_Y" is declared here. - #check: $()const E_Y = 305; -#nextln: $()Constant "E_Y" shadows constant of the same name. +#nextln: $()Constant "E_Y" shadows constant of the same name. \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars_alias/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars_alias/test.toml index 0d7bafcd27b..47228488d82 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars_alias/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/shadowing/shadowed_consts_and_vars_alias/test.toml @@ -1,9 +1,11 @@ category = "fail" #check: $()error - +#sameln: $()Constant of the same name already exists +#check: $()use lib::X as Y; +#nextln: $()Constant "Y" is already declared here. #check: $()const Y = 7; -#nextln: $()Constant "Y" was already defined in scope. +#nextln: $()Constant "Y" has the same name as an already declared constant. #check: $()error #sameln: $()Constants cannot be shadowed diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods1/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods1/test.toml index d97570c1c9c..e10407ebe8e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods1/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods1/test.toml @@ -1,3 +1,3 @@ category = "fail" -# check: $()ABI cannot define a method with the same name as its super-ABI "MySuperAbi" \ No newline at end of file +# check: $()ABI cannot define a method of the same name as its super-ABI "MySuperAbi" \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods2/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods2/test.toml index 846a2d64e8f..748bbbd6c3e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods2/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods2/test.toml @@ -1,3 +1,3 @@ category = "fail" -# check: $()ABI cannot define a method with the same name as its super-ABI "MySuperSuperAbi" \ No newline at end of file +# check: $()ABI cannot define a method of the same name as its super-ABI "MySuperSuperAbi" \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods6/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods6/test.toml index 2e420db800d..5841221adfd 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods6/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods6/test.toml @@ -2,4 +2,4 @@ category = "fail" # check: $()error # check: $()fn method() {} -# check: $()ABI cannot define a method with the same name as its super-ABI "MySuperAbi" \ No newline at end of file +# check: $()ABI cannot define a method of the same name as its super-ABI "MySuperAbi" \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods7/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods7/test.toml index c2230c44ed5..bdd72aa2de2 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods7/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods7/test.toml @@ -1,4 +1,4 @@ category = "fail" # check: $()error -# check: $()ABI cannot define a method with the same name as its super-ABI "MySuperAbi" \ No newline at end of file +# check: $()ABI cannot define a method of the same name as its super-ABI "MySuperAbi" \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods8/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods8/test.toml index 2e420db800d..5841221adfd 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods8/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods8/test.toml @@ -2,4 +2,4 @@ category = "fail" # check: $()error # check: $()fn method() {} -# check: $()ABI cannot define a method with the same name as its super-ABI "MySuperAbi" \ No newline at end of file +# check: $()ABI cannot define a method of the same name as its super-ABI "MySuperAbi" \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods9/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods9/test.toml index 846a2d64e8f..748bbbd6c3e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods9/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/superabi_duplicate_methods9/test.toml @@ -1,3 +1,3 @@ category = "fail" -# check: $()ABI cannot define a method with the same name as its super-ABI "MySuperSuperAbi" \ No newline at end of file +# check: $()ABI cannot define a method of the same name as its super-ABI "MySuperSuperAbi" \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/json_abi_oracle.json deleted file mode 100644 index ad50b55d54c..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/json_abi_oracle.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "configurables": [], - "functions": [ - { - "attributes": null, - "inputs": [], - "name": "main", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - } - ], - "loggedTypes": [], - "messagesTypes": [], - "types": [ - { - "components": null, - "type": "u64", - "typeId": 0, - "typeParameters": null - } - ] -} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/json_abi_oracle_new_encoding.json deleted file mode 100644 index 068da3305ab..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/json_abi_oracle_new_encoding.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "configurables": [], - "encoding": "1", - "functions": [ - { - "attributes": null, - "inputs": [], - "name": "main", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - } - ], - "loggedTypes": [], - "messagesTypes": [], - "types": [ - { - "components": null, - "type": "u64", - "typeId": 0, - "typeParameters": null - } - ] -} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/in_structs.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/in_structs.sw new file mode 100644 index 00000000000..30fc4af8cd2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/in_structs.sw @@ -0,0 +1,203 @@ +library; + +use ::lib::return_me; + +use ::lib::LIB_X; +use ::lib::LIB_Y as ALIAS_LIB_Y; + +const MOD_X: u64 = 8; + +const NUMBER_1: u64 = 7; +const NUMBER_2: u64 = 14; +const NUMBER_3: u64 = 5; + +const TRUE: bool = true; +const FALSE: bool = false; + +struct S { + x: u64, + b: bool, +} + +struct StructWithConstNames { + MOD_X: u64, + LOCAL_X: u64, + LIB_X: u64, + ALIAS_LIB_Y: u64, +} + +pub fn test() { + let a = match return_me(S { x: NUMBER_3, b: true }) { + S { x: NUMBER_1, b: _ } => 1, + S { x: NUMBER_2, b: _ } => 2, + S { x: NUMBER_3, b: _ } => 42, + _ => 1111, + }; + + assert_eq(a, 42); + + let b = match return_me(S { x: 0, b: TRUE }) { + S { x: _, b: TRUE } => 42, + S { x: _, b: FALSE } => 3, + }; + + assert_eq(b, 42); + + const LOCAL_X: u64 = 13; + + let c = match return_me(S { x: MOD_X, b: true }) { + S { x: MOD_X, b: _ } => { + 42 + }, + S { x: LOCAL_X, b: _ } => { + 4 + }, + S { x: LIB_X, b: _ } => { + 5 + }, + S { x: ALIAS_LIB_Y, b: _ } => { + 6 + }, + _ => 2222, + }; + + assert_eq(c, 42); + + let c = match return_me(S { x: LOCAL_X, b: true }) { + S { x: MOD_X, b: _ } => { + 7 + }, + S { x: LOCAL_X, b: _ } => { + 42 + }, + S { x: LIB_X, b: _ } => { + 8 + }, + S { x: ALIAS_LIB_Y, b: _ } => { + 9 + }, + _ => 3333, + }; + + assert_eq(c, 42); + + let c = match return_me(S { x: LIB_X, b: true }) { + S { x: MOD_X, b: _ } => { + 10 + }, + S { x: LOCAL_X, b: _ } => { + 11 + }, + S { x: LIB_X, b: _ } => { + 42 + }, + S { x: ALIAS_LIB_Y, b: _ } => { + 12 + }, + _ => 4444, + }; + + assert_eq(c, 42); + + let c = match return_me(S { x: ALIAS_LIB_Y, b: true }) { + S { x: MOD_X, b: _ } => { + 13 + }, + S { x: LOCAL_X, b: _ } => { + 14 + }, + S { x: LIB_X, b: _ } => { + 15 + }, + S { x: ALIAS_LIB_Y, b: _ } => { + 42 + }, + _ => 5555, + }; + + assert_eq(c, 42); + + let c = match return_me(S { x: MOD_X, b: true }) { + S { x: MOD_X, b: _ } | S { x: LOCAL_X, b: _ } | S { x: LIB_X, b: _ } => { + 42 + }, + S { x: ALIAS_LIB_Y, b: _ } => { + 16 + }, + _ => 6666, + }; + + assert_eq(c, 42); + + let c = match return_me(S { x: LOCAL_X, b: true }) { + S { x: MOD_X, b: _ } | S { x: LOCAL_X, b: _ } | S { x: LIB_X, b: _ } => { + 42 + }, + S { x: ALIAS_LIB_Y, b: _ } => { + 17 + }, + _ => 7777, + }; + + assert_eq(c, 42); + + let c = match return_me(S { x: LIB_X, b: true }) { + S { x: MOD_X, b: _ } | S { x: LOCAL_X, b: _ } | S { x: LIB_X, b: _ } => { + 42 + }, + S { x: ALIAS_LIB_Y, b: _ } => { + 18 + }, + _ => 8888, + }; + + assert_eq(c, 42); + + let c = match return_me(S { x: ALIAS_LIB_Y, b: true }) { + S { x: MOD_X, b: _ } | S { x: LOCAL_X, b: _ } | S { x: LIB_X, b: _ } => { + 19 + }, + S { x: ALIAS_LIB_Y, b: _ } => { + 42 + }, + _ => 9999, + }; + + assert_eq(c, 42); + + let s = StructWithConstNames { + MOD_X, + LOCAL_X, + LIB_X, + ALIAS_LIB_Y, + }; + + let c = match return_me(s) { + StructWithConstNames { MOD_X: 0u64, LOCAL_X: _, LIB_X: _, ALIAS_LIB_Y: _ } => { + 20 + }, + StructWithConstNames { MOD_X: MOD_X, LOCAL_X: LOCAL_X, LIB_X: LIB_X, ALIAS_LIB_Y: ALIAS_LIB_Y } => { + 42 + }, + _ => 9999, + }; + + let s = StructWithConstNames { + MOD_X: 0, + LOCAL_X: 0, + LIB_X: 0, + ALIAS_LIB_Y: 0, + }; + + let c = match return_me(s) { + StructWithConstNames { MOD_X: MOD_X, LOCAL_X: LOCAL_X, LIB_X: LIB_X, ALIAS_LIB_Y: ALIAS_LIB_Y } => { + 21 + }, + StructWithConstNames { MOD_X: 0u64, LOCAL_X: 0u64, LIB_X: 0u64, ALIAS_LIB_Y: 0u64 } => { + 42 + }, + _ => 10000, + }; + + assert_eq(c, 42); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/lib.sw index 09f06e62d38..633356dd214 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/lib.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/lib.sw @@ -1,4 +1,8 @@ library; -pub const LIB_X = 1021; -pub const LIB_Y = 1034; +pub const LIB_X: u64 = 1021; +pub const LIB_Y: u64 = 1034; + +pub fn return_me(x: T) -> T { + x +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw index 16e2a8600da..ffa92ace5e7 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw @@ -1,161 +1,11 @@ script; mod lib; - -use ::lib::LIB_X; -use ::lib::LIB_Y as ALIAS_LIB_Y; - -const MOD_X = 8; - -const NUMBER_1: u64 = 7; -const NUMBER_2: u64 = 14; -const NUMBER_3: u64 = 5; - -const TRUE: bool = true; -const FALSE: bool = false; +mod top_level; +mod in_structs; fn main() -> u64 { - let a = match return_me(NUMBER_3) { - NUMBER_1 => 1, - NUMBER_2 => 1, - NUMBER_3 => 42, - other => other, - }; - - assert(a == 42); - - let b = match return_me(TRUE) { - TRUE => 42, - FALSE => 1, - }; - - assert(b == 42); - - const MAIN_X = 13; - - let c = match return_me(MOD_X) { - MOD_X => { - 42 - }, - MAIN_X => { - 1 - }, - LIB_X => { - 1 - }, - ALIAS_LIB_Y => { - 1 - }, - _ => 9999, - }; - - assert(c == 42); - - let c = match return_me(MAIN_X) { - MOD_X => { - 1 - }, - MAIN_X => { - 42 - }, - LIB_X => { - 1 - }, - ALIAS_LIB_Y => { - 1 - }, - _ => 9999, - }; - - assert(c == 42); - - let c = match return_me(LIB_X) { - MOD_X => { - 1 - }, - MAIN_X => { - 1 - }, - LIB_X => { - 42 - }, - ALIAS_LIB_Y => { - 1 - }, - _ => 9999, - }; - - assert(c == 42); - - let c = match return_me(ALIAS_LIB_Y) { - MOD_X => { - 1 - }, - MAIN_X => { - 1 - }, - LIB_X => { - 1 - }, - ALIAS_LIB_Y => { - 42 - }, - _ => 9999, - }; - - assert(c == 42); - - let c = match return_me(MOD_X) { - MOD_X | MAIN_X | LIB_X => { - 42 - }, - ALIAS_LIB_Y => { - 1 - }, - _ => 9999, - }; - - assert(c == 42); - - let c = match return_me(MAIN_X) { - MOD_X | MAIN_X | LIB_X => { - 42 - }, - ALIAS_LIB_Y => { - 1 - }, - _ => 9999, - }; - - assert(c == 42); - - let c = match return_me(LIB_X) { - MOD_X | MAIN_X | LIB_X => { - 42 - }, - ALIAS_LIB_Y => { - 1 - }, - _ => 9999, - }; - - assert(c == 42); - - let c = match return_me(ALIAS_LIB_Y) { - MOD_X | MAIN_X | LIB_X => { - 1 - }, - ALIAS_LIB_Y => { - 42 - }, - _ => 9999, - }; - - assert(c == 42); - - a + b + c + ::top_level::test(); + ::in_structs::test(); + 42 } - -fn return_me(x: T) -> T { - x -} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/top_level.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/top_level.sw new file mode 100644 index 00000000000..28875f81696 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/top_level.sw @@ -0,0 +1,155 @@ +library; + +use ::lib::return_me; + +use ::lib::LIB_X; +use ::lib::LIB_Y as ALIAS_LIB_Y; + +const MOD_X: u64 = 8; + +const NUMBER_1: u64 = 7; +const NUMBER_2: u64 = 14; +const NUMBER_3: u64 = 5; + +const TRUE: bool = true; +const FALSE: bool = false; + +pub fn test() { + let a = match return_me(NUMBER_3) { + NUMBER_1 => 1, + NUMBER_2 => 2, + NUMBER_3 => 42, + other => other, + }; + + assert_eq(a, 42); + + let b = match return_me(TRUE) { + TRUE => 42, + FALSE => 3, + }; + + assert_eq(b, 42); + + const LOCAL_X: u64 = 13; + + let c = match return_me(MOD_X) { + MOD_X => { + 42 + }, + LOCAL_X => { + 4 + }, + LIB_X => { + 5 + }, + ALIAS_LIB_Y => { + 6 + }, + _ => 1111, + }; + + assert_eq(c, 42); + + let c = match return_me(LOCAL_X) { + MOD_X => { + 7 + }, + LOCAL_X => { + 42 + }, + LIB_X => { + 8 + }, + ALIAS_LIB_Y => { + 9 + }, + _ => 2222, + }; + + assert_eq(c, 42); + + let c = match return_me(LIB_X) { + MOD_X => { + 10 + }, + LOCAL_X => { + 11 + }, + LIB_X => { + 42 + }, + ALIAS_LIB_Y => { + 12 + }, + _ => 3333, + }; + + assert_eq(c, 42); + + let c = match return_me(ALIAS_LIB_Y) { + MOD_X => { + 13 + }, + LOCAL_X => { + 14 + }, + LIB_X => { + 15 + }, + ALIAS_LIB_Y => { + 42 + }, + _ => 4444, + }; + + assert_eq(c, 42); + + let c = match return_me(MOD_X) { + MOD_X | LOCAL_X | LIB_X => { + 42 + }, + ALIAS_LIB_Y => { + 16 + }, + _ => 5555, + }; + + assert_eq(c, 42); + + let c = match return_me(LOCAL_X) { + MOD_X | LOCAL_X | LIB_X => { + 42 + }, + ALIAS_LIB_Y => { + 17 + }, + _ => 6666, + }; + + assert_eq(c, 42); + + let c = match return_me(LIB_X) { + MOD_X | LOCAL_X | LIB_X => { + 42 + }, + ALIAS_LIB_Y => { + 18 + }, + _ => 7777, + }; + + assert_eq(c, 42); + + let c = match return_me(ALIAS_LIB_Y) { + MOD_X | LOCAL_X | LIB_X => { + 19 + }, + ALIAS_LIB_Y => { + 42 + }, + _ => 8888, + }; + + assert_eq(c, 42); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/test.toml index 48fc96f6270..2e1e1832422 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/test.toml @@ -1,5 +1,4 @@ category = "run" -expected_result = { action = "return", value = 126 } -expected_result_new_encoding = { action = "return_data", value = "000000000000007E" } -validate_abi = true +expected_result = { action = "return", value = 42 } +expected_result_new_encoding = { action = "return_data", value = "000000000000002A" } expected_warnings = 1 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/src/lib.sw index 1b56f4e904f..44e1420d02a 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/src/lib.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/src/lib.sw @@ -1,7 +1,9 @@ library; -pub const X1 = 5; -pub const X2 = 5; +pub const X1: u64 = 5; +pub const X2: u64 = 5; +pub const X3: u64 = 5; + pub struct MyStruct11 {} pub enum MyEnum12 {} pub trait MyTrait13 {} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/src/main.sw index 06649cbd36a..e59fe4c773c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/src/main.sw @@ -6,7 +6,7 @@ mod lib; use lib::*; // const shadowing an imported const with glob -const X1 = 7; +const X1: u64 = 0; // types and traits shadowing imported items with glob struct MyStruct11 {} @@ -32,8 +32,13 @@ enum MyAbi24 {} trait MyAbi34 {} abi MyAbi44 {} +configurable { + X3: u64 = 22, +} -fn main() { +fn main() -> u64 { // var shadowing an imported const with glob - let X2 = 4; + let X2 = 20; + + X1 + X2 + X3 } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/test.toml index 75b5f2ef5a2..81416a67cb2 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/shadowing/shadowed_glob_imports/test.toml @@ -1,2 +1,4 @@ -category = "compile" +category = "run" +expected_result = { action = "return", value = 42 } +expected_result_new_encoding = { action = "return_data", value = "000000000000002A" } expected_warnings = 27 diff --git a/test/src/ir_generation/mod.rs b/test/src/ir_generation/mod.rs index e79226326d5..0c6107aaccf 100644 --- a/test/src/ir_generation/mod.rs +++ b/test/src/ir_generation/mod.rs @@ -8,8 +8,8 @@ use std::{ use anyhow::Result; use colored::Colorize; use sway_core::{ - compile_ir_context_to_finalized_asm, compile_to_ast, ir_generation::compile_program, namespace, - BuildTarget, Engines, + compile_ir_context_to_finalized_asm, compile_to_ast, ir_generation::compile_program, + language::Visibility, namespace, BuildTarget, Engines, }; use sway_error::handler::Handler; @@ -171,16 +171,16 @@ pub(super) async fn run( // TODO the way modules are built for these tests, new_encoding is not working. experimental.new_encoding = false; - // Compile core library and reuse it when compiling tests. - let engines = Engines::default(); - let build_target = BuildTarget::default(); - let mut core_lib = compile_core(build_target, &engines, experimental); - // Create new initial namespace for every test by reusing the precompiled // standard libraries. The namespace, thus its root module, must have the // name set. const PACKAGE_NAME: &str = "test_lib"; - core_lib.name = Some(sway_types::Ident::new_no_span(PACKAGE_NAME.to_string())); + let core_lib_name = sway_types::Ident::new_no_span(PACKAGE_NAME.to_string()); + + // 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, experimental); // Find all the tests. let all_tests = discover_test_files(); @@ -527,6 +527,7 @@ fn discover_test_files() -> Vec { } fn compile_core( + lib_name: sway_types::Ident, build_target: BuildTarget, engines: &Engines, experimental: ExperimentalFlags, @@ -563,7 +564,11 @@ fn compile_core( .submodules() .into_iter() .fold( - namespace::Module::default(), + 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 @@ -571,7 +576,7 @@ fn compile_core( ); // Create a module for std and insert the core module. - let mut std_module = namespace::Module::default(); + let mut std_module = namespace::Module::new(lib_name, Visibility::Private, None); std_module.insert_submodule("core".to_owned(), core_module); std_module }