From dda0f8bb4a748d98d6ad2a414163e05755e1de6e Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Sun, 12 Feb 2023 17:05:57 +0000 Subject: [PATCH] Changes TypeInfo::Custom to have call paths. (#4026) --- sway-core/src/abi_generation/evm_json_abi.rs | 2 +- sway-core/src/abi_generation/fuel_json_abi.rs | 2 +- .../language/parsed/expression/scrutinee.rs | 4 +- .../ast_node/declaration/impl_trait.rs | 2 +- .../match_expression/typed/typed_scrutinee.rs | 15 ++++-- .../ast_node/expression/typed_expression.rs | 2 +- .../typed_expression/method_application.rs | 2 +- .../typed_expression/struct_instantiation.rs | 4 +- .../src/semantic_analysis/namespace/root.rs | 53 ++++++++++++++++++- .../semantic_analysis/namespace/trait_map.rs | 14 ++--- .../semantic_analysis/node_dependencies.rs | 9 ++-- .../to_parsed_lang/convert_parse_tree.rs | 34 ++++++------ sway-core/src/type_system/engine.rs | 16 +++--- sway-core/src/type_system/id.rs | 12 ++--- sway-core/src/type_system/info.rs | 29 +++++----- sway-core/src/type_system/unify_check.rs | 4 +- sway-lsp/src/core/token.rs | 8 +-- sway-lsp/src/traverse/parsed_tree.rs | 16 +++--- sway-lsp/src/traverse/typed_tree.rs | 2 +- .../invalid_fully_qualified_type/Forc.lock | 3 ++ .../invalid_fully_qualified_type/Forc.toml | 6 +++ .../invalid_fully_qualified_type/src/foo.sw | 6 +++ .../invalid_fully_qualified_type/src/main.sw | 14 +++++ .../invalid_fully_qualified_type/test.toml | 7 +++ .../typeinfo_custom_callpath/Forc.lock | 13 +++++ .../typeinfo_custom_callpath/Forc.toml | 8 +++ .../json_abi_oracle.json | 25 +++++++++ .../typeinfo_custom_callpath/src/foo.sw | 6 +++ .../typeinfo_custom_callpath/src/main.sw | 21 ++++++++ .../typeinfo_custom_callpath/test.toml | 3 ++ .../typeinfo_custom_callpath2/Forc.lock | 13 +++++ .../typeinfo_custom_callpath2/Forc.toml | 8 +++ .../json_abi_oracle.json | 25 +++++++++ .../typeinfo_custom_callpath2/src/foo.sw | 6 +++ .../typeinfo_custom_callpath2/src/main.sw | 21 ++++++++ .../typeinfo_custom_callpath2/test.toml | 3 ++ .../Forc.lock | 13 +++++ .../Forc.toml | 8 +++ .../json_abi_oracle.json | 25 +++++++++ .../src/foo.sw | 6 +++ .../src/main.sw | 24 +++++++++ .../test.toml | 3 ++ 42 files changed, 416 insertions(+), 81 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/src/foo.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/src/foo.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/src/foo.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/src/foo.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/test.toml diff --git a/sway-core/src/abi_generation/evm_json_abi.rs b/sway-core/src/abi_generation/evm_json_abi.rs index 8aaa90b8f5a..554d53a9c5e 100644 --- a/sway-core/src/abi_generation/evm_json_abi.rs +++ b/sway-core/src/abi_generation/evm_json_abi.rs @@ -83,7 +83,7 @@ pub fn json_abi_str(type_info: &TypeInfo, type_engine: &TypeEngine) -> String { } .into(), Boolean => "bool".into(), - Custom { name, .. } => name.to_string(), + Custom { call_path, .. } => call_path.suffix.to_string(), Tuple(fields) => { let field_strs = fields .iter() diff --git a/sway-core/src/abi_generation/fuel_json_abi.rs b/sway-core/src/abi_generation/fuel_json_abi.rs index d2193d10c67..867cec2b51b 100644 --- a/sway-core/src/abi_generation/fuel_json_abi.rs +++ b/sway-core/src/abi_generation/fuel_json_abi.rs @@ -564,7 +564,7 @@ impl TypeInfo { } .into(), Boolean => "bool".into(), - Custom { name, .. } => name.to_string(), + Custom { call_path, .. } => call_path.suffix.to_string(), Tuple(fields) => { let field_strs = fields .iter() diff --git a/sway-core/src/language/parsed/expression/scrutinee.rs b/sway-core/src/language/parsed/expression/scrutinee.rs index 564c90deac7..a373f8f567b 100644 --- a/sway-core/src/language/parsed/expression/scrutinee.rs +++ b/sway-core/src/language/parsed/expression/scrutinee.rs @@ -131,7 +131,7 @@ impl Scrutinee { .. } => { let name = vec![TypeInfo::Custom { - name: struct_name.clone().suffix, + call_path: struct_name.clone(), type_arguments: None, }]; let fields = fields @@ -151,7 +151,7 @@ impl Scrutinee { } => { let enum_name = call_path.prefixes.last().unwrap_or(&call_path.suffix); let name = vec![TypeInfo::Custom { - name: enum_name.clone(), + call_path: enum_name.clone().into(), type_arguments: None, }]; let value = value.gather_approximate_typeinfo_dependencies(); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index b6cb2ebf707..002081bfb84 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -453,7 +453,7 @@ impl ty::TyImplTrait { let trait_name = CallPath { prefixes: vec![], suffix: match &type_implementing_for { - TypeInfo::Custom { name, .. } => name.clone(), + TypeInfo::Custom { call_path, .. } => call_path.suffix.clone(), _ => Ident::new_with_override("r#Self", type_implementing_for_span.clone()), }, is_absolute: false, 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 6250fd39753..0f8311ded66 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 @@ -221,8 +221,13 @@ fn type_check_enum( let decl_engine = ctx.decl_engine; - let enum_name = match call_path.prefixes.last() { - Some(enum_name) => enum_name, + let mut prefixes = call_path.prefixes.clone(); + let enum_callpath = match prefixes.pop() { + Some(enum_name) => CallPath { + suffix: enum_name, + prefixes, + is_absolute: call_path.is_absolute, + }, None => { errors.push(CompileError::EnumNotFound { name: call_path.suffix.clone(), @@ -235,13 +240,13 @@ fn type_check_enum( // find the enum definition from the name let unknown_decl = check!( - ctx.namespace.resolve_symbol(enum_name).cloned(), + ctx.namespace.resolve_call_path(&enum_callpath).cloned(), return err(warnings, errors), warnings, errors ); let mut enum_decl = check!( - unknown_decl.expect_enum(decl_engine, &enum_name.span()), + unknown_decl.expect_enum(decl_engine, &enum_callpath.span()), return err(warnings, errors), warnings, errors @@ -253,7 +258,7 @@ fn type_check_enum( &mut enum_decl, &mut [], EnforceTypeArguments::No, - &enum_name.span() + &enum_callpath.span() ), return err(warnings, errors), warnings, 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 ca7866ec8c2..1a29460e605 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 @@ -1026,7 +1026,7 @@ impl ty::TyExpression { let before_span = before.span(); let type_name = before.inner; let type_info = type_name_to_type_info_opt(&type_name).unwrap_or(TypeInfo::Custom { - name: type_name.clone(), + call_path: type_name.clone().into(), type_arguments: None, }); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index 4aca5f6789f..e4e26c265d6 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 @@ -268,7 +268,7 @@ pub(crate) fn type_check_method_application( } => { let mut prefixes = call_path_binding.inner.prefixes; prefixes.push(match &call_path_binding.inner.suffix { - (TypeInfo::Custom { name, .. }, ..) => name.clone(), + (TypeInfo::Custom { call_path, .. }, ..) => call_path.clone().suffix, (_, ident) => ident.clone(), }); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index 1c08ccdd9dd..fe934d725b4 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -53,11 +53,11 @@ pub(crate) fn struct_instantiation( return err(warnings, errors); } (_, true) => TypeInfo::Custom { - name: suffix, + call_path: suffix.into(), type_arguments: None, }, (_, false) => TypeInfo::Custom { - name: suffix, + call_path: suffix.into(), type_arguments: Some(type_arguments), }, }; diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index bbf307d39ae..5cb801d77d1 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -1,6 +1,10 @@ +use sway_error::error::CompileError; +use sway_types::Spanned; + use crate::{ - language::{ty, CallPath}, - CompileResult, Ident, + error::*, + language::{ty, CallPath, Visibility}, + CompileResult, Engines, Ident, }; use super::{module::Module, namespace::Namespace, Path}; @@ -36,6 +40,51 @@ impl Root { self.resolve_symbol(&symbol_path, &call_path.suffix) } + /// Resolve a symbol that is potentially prefixed with some path, e.g. `foo::bar::symbol`. + /// + /// This is short-hand for concatenating the `mod_path` with the `call_path`'s prefixes and + /// then calling `resolve_symbol` with the resulting path and call_path's suffix. + /// + /// When `call_path` contains prefixes and the resolved declaration visibility is not public + /// an error is thrown. + pub(crate) fn resolve_call_path_with_visibility_check( + &self, + engines: Engines<'_>, + mod_path: &Path, + call_path: &CallPath, + ) -> CompileResult<&ty::TyDeclaration> { + let mut warnings = vec![]; + let mut errors = vec![]; + + let result = self.resolve_call_path(mod_path, call_path); + + // In case there are no prefixes we don't need to check visibility + if call_path.prefixes.is_empty() { + return result; + } + + if let CompileResult { + value: Some(decl), .. + } = result + { + let visibility = check!( + decl.visibility(engines.de()), + return err(warnings, errors), + warnings, + errors + ); + if visibility != Visibility::Public { + errors.push(CompileError::ImportPrivateSymbol { + name: call_path.suffix.clone(), + span: call_path.suffix.span(), + }); + return err(warnings, errors); + } + } + + result + } + /// Given a path to a module and the identifier of a symbol within that module, resolve its /// declaration. /// diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index faeec68f008..fc3044c1adf 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -118,7 +118,7 @@ impl TraitMap { let trait_type_id = type_engine.insert( decl_engine, TypeInfo::Custom { - name: trait_name.suffix.clone(), + call_path: trait_name.suffix.clone().into(), type_arguments: if trait_type_args.is_empty() { None } else { @@ -146,7 +146,7 @@ impl TraitMap { let map_trait_type_id = type_engine.insert( decl_engine, TypeInfo::Custom { - name: map_trait_name_suffix.clone(), + call_path: map_trait_name_suffix.clone().into(), type_arguments: if map_trait_type_args.is_empty() { None } else { @@ -706,7 +706,7 @@ impl TraitMap { let map_trait_type_id = type_engine.insert( decl_engine, TypeInfo::Custom { - name: suffix.name.clone(), + call_path: suffix.name.clone().into(), type_arguments: if suffix.args.is_empty() { None } else { @@ -732,7 +732,7 @@ impl TraitMap { let constraint_type_id = type_engine.insert( decl_engine, TypeInfo::Custom { - name: constraint_trait_name.suffix.clone(), + call_path: constraint_trait_name.suffix.clone().into(), type_arguments: if constraint_type_arguments.is_empty() { None } else { @@ -823,15 +823,15 @@ pub(crate) fn are_equal_minus_dynamic_types( // these cases may contain dynamic types ( TypeInfo::Custom { - name: l_name, + call_path: l_name, type_arguments: l_type_args, }, TypeInfo::Custom { - name: r_name, + call_path: r_name, type_arguments: r_type_args, }, ) => { - l_name == r_name + l_name.suffix == r_name.suffix && l_type_args .unwrap_or_default() .iter() diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index 7bf04c53baa..7f39f515d1d 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -650,10 +650,11 @@ impl Dependencies { .. } => self.gather_from_call_path(abi_name, false, false), TypeInfo::Custom { - name, + call_path: name, type_arguments, } => { - self.deps.insert(DependentSymbol::Symbol(name.clone())); + self.deps + .insert(DependentSymbol::Symbol(name.clone().suffix)); match type_arguments { Some(type_arguments) => { self.gather_from_type_arguments(type_engine, type_arguments) @@ -807,7 +808,9 @@ fn type_info_name(type_info: &TypeInfo) -> String { IntegerBits::SixtyFour => "uint64", }, TypeInfo::Boolean => "bool", - TypeInfo::Custom { name, .. } => name.as_str(), + TypeInfo::Custom { + call_path: name, .. + } => name.suffix.as_str(), TypeInfo::Tuple(fields) if fields.is_empty() => "unit", TypeInfo::Tuple(..) => "tuple", TypeInfo::SelfType => "self", diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index 9a63d349994..883cd841cbf 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -322,7 +322,7 @@ fn item_struct_to_struct_declaration( .collect::, _>>()?; if fields.iter().any( - |field| matches!(&field.type_info, TypeInfo::Custom { name, ..} if name == &item_struct.name), + |field| matches!(&field.type_info, TypeInfo::Custom { call_path, ..} if call_path.suffix == item_struct.name), ) { errors.push(ConvertParseTreeError::RecursiveType { span: span.clone() }); } @@ -380,7 +380,7 @@ fn item_enum_to_enum_declaration( .collect::, _>>()?; if variants.iter().any(|variant| { - matches!(&variant.type_info, TypeInfo::Custom { name, ..} if name == &item_enum.name) + matches!(&variant.type_info, TypeInfo::Custom { call_path, ..} if call_path.suffix == item_enum.name) }) { errors.push(ConvertParseTreeError::RecursiveType { span: span.clone() }); } @@ -892,7 +892,7 @@ fn generic_params_opt_to_type_parameters( let custom_type = type_engine.insert( decl_engine, TypeInfo::Custom { - name: ident.clone(), + call_path: ident.clone().into(), type_arguments: None, }, ); @@ -3278,7 +3278,7 @@ fn ty_to_type_parameter( let custom_type = type_engine.insert( decl_engine, TypeInfo::Custom { - name: name_ident.clone(), + call_path: name_ident.clone().into(), type_arguments: None, }, ); @@ -3520,15 +3520,14 @@ fn path_type_to_type_info( root_opt, prefix: PathTypeSegment { name, generics_opt }, suffix, - } = path_type; - - if root_opt.is_some() || !suffix.is_empty() { - let error = ConvertParseTreeError::FullySpecifiedTypesNotSupported { span }; - return Err(handler.emit_err(error.into())); - } + } = path_type.clone(); let type_info = match type_name_to_type_info_opt(&name) { Some(type_info) => { + if root_opt.is_some() || !suffix.is_empty() { + let error = ConvertParseTreeError::FullySpecifiedTypesNotSupported { span }; + return Err(handler.emit_err(error.into())); + } if let Some((_, generic_args)) = generics_opt { let error = ConvertParseTreeError::GenericsNotSupportedHere { span: generic_args.span(), @@ -3539,6 +3538,10 @@ fn path_type_to_type_info( } None => { if name.as_str() == "ContractCaller" { + if root_opt.is_some() || !suffix.is_empty() { + let error = ConvertParseTreeError::FullySpecifiedTypesNotSupported { span }; + return Err(handler.emit_err(error.into())); + } let generic_ty = match { generics_opt.and_then(|(_, generic_args)| { iter_to_array(generic_args.parameters.into_inner()) @@ -3567,14 +3570,11 @@ fn path_type_to_type_info( address: None, } } else { - let type_arguments = match generics_opt { - Some((_double_colon_token, generic_args)) => { - generic_args_to_type_arguments(context, handler, engines, generic_args)? - } - None => Vec::new(), - }; + let (call_path, type_arguments) = path_type_to_call_path_and_type_arguments( + context, handler, engines, path_type, + )?; TypeInfo::Custom { - name, + call_path, type_arguments: Some(type_arguments), } } diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index c9c3c4b78c4..f504351d6b1 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -402,19 +402,21 @@ impl TypeEngine { let module_path = type_info_prefix.unwrap_or(mod_path); let type_id = match self.get(type_id) { TypeInfo::Custom { - name, + call_path, type_arguments, } => { match namespace .root() - .resolve_symbol(module_path, &name) + .resolve_call_path_with_visibility_check(engines, module_path, &call_path) .ok(&mut warnings, &mut errors) .cloned() { Some(ty::TyDeclaration::StructDeclaration(original_id)) => { // get the copy from the declaration engine let mut new_copy = check!( - CompileResult::from(decl_engine.get_struct(original_id, &name.span())), + CompileResult::from( + decl_engine.get_struct(original_id, &call_path.span()) + ), return err(warnings, errors), warnings, errors @@ -448,7 +450,9 @@ impl TypeEngine { Some(ty::TyDeclaration::EnumDeclaration(original_id)) => { // get the copy from the declaration engine let mut new_copy = check!( - CompileResult::from(decl_engine.get_enum(original_id, &name.span())), + CompileResult::from( + decl_engine.get_enum(original_id, &call_path.span()) + ), return err(warnings, errors), warnings, errors @@ -482,8 +486,8 @@ impl TypeEngine { Some(ty::TyDeclaration::GenericTypeForFunctionScope { type_id, .. }) => type_id, _ => { errors.push(CompileError::UnknownTypeName { - name: name.to_string(), - span: name.span(), + name: call_path.to_string(), + span: call_path.span(), }); self.insert(decl_engine, TypeInfo::ErrorRecovery) } diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index c3990e51fa9..734f07d2c3b 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -177,7 +177,7 @@ impl ReplaceSelfType for TypeId { } } TypeInfo::Custom { - name, + call_path, type_arguments, } => { let mut need_to_create_new = false; @@ -198,7 +198,7 @@ impl ReplaceSelfType for TypeId { Some(type_engine.insert( decl_engine, TypeInfo::Custom { - name, + call_path, type_arguments, }, )) @@ -307,19 +307,19 @@ impl TypeId { ) -> bool { match (type_engine.get(self), type_engine.get(resolved_type_id)) { ( - TypeInfo::Custom { name, .. }, + TypeInfo::Custom { call_path, .. }, TypeInfo::Enum { call_path: enum_call_path, .. }, - ) => name != enum_call_path.suffix, + ) => call_path.suffix != enum_call_path.suffix, ( - TypeInfo::Custom { name, .. }, + TypeInfo::Custom { call_path, .. }, TypeInfo::Struct { call_path: struct_call_path, .. }, - ) => name != struct_call_path.suffix, + ) => call_path.suffix != struct_call_path.suffix, (TypeInfo::Custom { .. }, _) => true, _ => false, } diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index e168f48db49..c930a576f93 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -115,7 +115,7 @@ pub enum TypeInfo { /// At parse time, there is no sense of scope, so this determination is not made /// until the semantic analysis stage. Custom { - name: Ident, + call_path: CallPath, type_arguments: Option>, }, SelfType, @@ -191,10 +191,10 @@ impl HashWithEngines for TypeInfo { trait_constraints.hash(state, engines); } TypeInfo::Custom { - name, + call_path, type_arguments, } => { - name.hash(state); + call_path.hash(state); type_arguments.as_deref().hash(state, engines); } TypeInfo::Storage { fields } => { @@ -238,14 +238,17 @@ impl PartialEqWithEngines for TypeInfo { (Self::Placeholder(l), Self::Placeholder(r)) => l.eq(r, engines), ( Self::Custom { - name: l_name, + call_path: l_name, type_arguments: l_type_args, }, Self::Custom { - name: r_name, + call_path: r_name, type_arguments: r_type_args, }, - ) => l_name == r_name && l_type_args.as_deref().eq(&r_type_args.as_deref(), engines), + ) => { + l_name.suffix == r_name.suffix + && l_type_args.as_deref().eq(&r_type_args.as_deref(), engines) + } (Self::Str(l), Self::Str(r)) => l.val() == r.val(), (Self::UnsignedInteger(l), Self::UnsignedInteger(r)) => l == r, ( @@ -337,7 +340,9 @@ impl DisplayWithEngines for TypeInfo { } .into(), Boolean => "bool".into(), - Custom { name, .. } => format!("unresolved {}", name.as_str()), + Custom { call_path, .. } => { + format!("unresolved {}", call_path.suffix.as_str()) + } Tuple(fields) => { let field_strs = fields .iter() @@ -799,7 +804,7 @@ impl TypeInfo { err(warnings, errors) } TypeInfo::Custom { - name, + call_path, type_arguments: other_type_arguments, } => { if other_type_arguments.is_some() { @@ -807,7 +812,7 @@ impl TypeInfo { err(warnings, errors) } else { let type_info = TypeInfo::Custom { - name, + call_path, type_arguments: Some(type_arguments), }; ok(type_info, warnings, errors) @@ -1374,11 +1379,11 @@ impl TypeInfo { } ( Self::Custom { - name: l_name, + call_path: l_name, type_arguments: l_type_args, }, Self::Custom { - name: r_name, + call_path: r_name, type_arguments: r_type_args, }, ) => { @@ -1394,7 +1399,7 @@ impl TypeInfo { .iter() .map(|x| type_engine.get(x.type_id)) .collect::>(); - l_name == r_name && types_are_subset_of(engines, &l_types, &r_types) + l_name.suffix == r_name.suffix && types_are_subset_of(engines, &l_types, &r_types) } ( Self::Enum { diff --git a/sway-core/src/type_system/unify_check.rs b/sway-core/src/type_system/unify_check.rs index 05c9d75066f..30ddef5da49 100644 --- a/sway-core/src/type_system/unify_check.rs +++ b/sway-core/src/type_system/unify_check.rs @@ -147,11 +147,11 @@ impl<'a> UnifyCheck<'a> { ( Custom { - name: l_name, + call_path: l_name, type_arguments: l_type_args, }, Custom { - name: r_name, + call_path: r_name, type_arguments: r_type_args, }, ) => { diff --git a/sway-lsp/src/core/token.rs b/sway-lsp/src/core/token.rs index a1be1506f1d..3b78ac83d35 100644 --- a/sway-lsp/src/core/token.rs +++ b/sway-lsp/src/core/token.rs @@ -156,10 +156,10 @@ pub fn to_ident_key(ident: &Ident) -> (Ident, Span) { /// Use the [TypeId] to look up the associated [TypeInfo] and return the [Ident] if one is found. pub fn ident_of_type_id(type_engine: &TypeEngine, type_id: &TypeId) -> Option { match type_engine.get(*type_id) { - TypeInfo::UnknownGeneric { name, .. } | TypeInfo::Custom { name, .. } => Some(name), - TypeInfo::Enum { call_path, .. } | TypeInfo::Struct { call_path, .. } => { - Some(call_path.suffix) - } + TypeInfo::UnknownGeneric { name, .. } => Some(name), + TypeInfo::Enum { call_path, .. } + | TypeInfo::Struct { call_path, .. } + | TypeInfo::Custom { call_path, .. } => Some(call_path.suffix), _ => None, } } diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index 3713a544a8c..daf5409b893 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -301,7 +301,7 @@ impl<'a> ParsedTree<'a> { } Declaration::ImplSelf(impl_self) => { if let TypeInfo::Custom { - name, + call_path, type_arguments, } = &impl_self.type_implementing_for { @@ -309,7 +309,8 @@ impl<'a> ParsedTree<'a> { AstToken::Declaration(declaration.clone()), SymbolKind::Struct, ); - self.tokens.insert(to_ident_key(name), token.clone()); + self.tokens + .insert(to_ident_key(&call_path.suffix), token.clone()); if let Some(type_arguments) = type_arguments { for type_arg in type_arguments { self.collect_type_arg(type_arg, &token); @@ -839,7 +840,7 @@ impl<'a> ParsedTree<'a> { } } TypeInfo::Custom { - name, + call_path, type_arguments, } => { if let Some(type_args) = type_arguments { @@ -852,7 +853,7 @@ impl<'a> ParsedTree<'a> { token.kind = symbol_kind; token.type_def = Some(TypeDefinition::TypeId(type_argument.type_id)); self.tokens - .insert(to_ident_key(&Ident::new(name.span())), token); + .insert(to_ident_key(&Ident::new(call_path.suffix.span())), token); } _ => { let symbol_kind = type_info_to_symbol_kind(self.type_engine, &type_info); @@ -974,11 +975,12 @@ impl<'a> ParsedTree<'a> { } } TypeInfo::Custom { - name, + call_path, type_arguments, } => { - token.type_def = Some(TypeDefinition::Ident(name.clone())); - self.tokens.insert(to_ident_key(name), token.clone()); + token.type_def = Some(TypeDefinition::Ident(call_path.suffix.clone())); + self.tokens + .insert(to_ident_key(&call_path.suffix), token.clone()); if let Some(type_arguments) = type_arguments { for type_arg in type_arguments { self.collect_type_arg(type_arg, &token); diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index f8d25447cde..881c4245b31 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -1133,7 +1133,7 @@ impl<'a> TypedTree<'a> { } TypeInfo::Custom { type_arguments, - name, + call_path: name, } => { if let Some(token) = self .tokens diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/Forc.lock new file mode 100644 index 00000000000..98157f37b8c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/Forc.lock @@ -0,0 +1,3 @@ +[[package]] +name = 'invalid_fully_qualified_type' +source = 'member' diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/Forc.toml new file mode 100644 index 00000000000..8f5c89a29e7 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/Forc.toml @@ -0,0 +1,6 @@ +[project] +name = "invalid_fully_qualified_type" +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +implicit-std = false \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/src/foo.sw b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/src/foo.sw new file mode 100644 index 00000000000..89d0f697cfa --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/src/foo.sw @@ -0,0 +1,6 @@ +library foo; + +enum Foo { + A: (), + B: (), +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/src/main.sw new file mode 100644 index 00000000000..e3e124d68f1 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/src/main.sw @@ -0,0 +1,14 @@ +script; + +dep foo; + +struct Bar { + baz: foo::foo::Foo +} + +struct Bar2 { + baz: foo::Foo +} + +fn main() { +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/test.toml new file mode 100644 index 00000000000..a84fcd8fc89 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_fully_qualified_type/test.toml @@ -0,0 +1,7 @@ +category = "fail" + +# check: $()baz: foo::foo::Foo +# nextln:$()Unknown type name "foo::foo::Foo". + +# check: $()baz: foo::Foo +# nextln:$()Symbol "Foo" is private. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/Forc.lock new file mode 100644 index 00000000000..527be7ee66e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-0492F2320BFFFD1E' + +[[package]] +name = 'std' +source = 'path+from-root-0492F2320BFFFD1E' +dependencies = ['core'] + +[[package]] +name = 'typeinfo_custom_callpath' +source = 'member' +dependencies = ['std'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/Forc.toml new file mode 100644 index 00000000000..d5b5168d440 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "typeinfo_custom_callpath" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/json_abi_oracle.json new file mode 100644 index 00000000000..fad72a08f17 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": [], + "type": "()", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/src/foo.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/src/foo.sw new file mode 100644 index 00000000000..898bbe8b3f2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/src/foo.sw @@ -0,0 +1,6 @@ +library foo; + +pub enum Foo { + A: (), + B: (), +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/src/main.sw new file mode 100644 index 00000000000..a00225284fb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/src/main.sw @@ -0,0 +1,21 @@ +script; + +dep foo; + +struct Bar { + baz: foo::Foo +} + + +fn main() { + let x = Bar { + baz: foo::Foo::A + }; + + let b = match x { + Bar { baz: foo::Foo::A(_) } => true, + _ => false, + }; + + assert(b); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/test.toml new file mode 100644 index 00000000000..44ca8ea93c4 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath/test.toml @@ -0,0 +1,3 @@ +category = "run" +expected_result = { action = "return", value = 0 } +validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/Forc.lock new file mode 100644 index 00000000000..f6131c8ee73 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-0ACF6FE48FDFC4A8' + +[[package]] +name = 'std' +source = 'path+from-root-0ACF6FE48FDFC4A8' +dependencies = ['core'] + +[[package]] +name = 'typeinfo_custom_callpath2' +source = 'member' +dependencies = ['std'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/Forc.toml new file mode 100644 index 00000000000..0b567cce62a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "typeinfo_custom_callpath2" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/json_abi_oracle.json new file mode 100644 index 00000000000..fad72a08f17 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": [], + "type": "()", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/src/foo.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/src/foo.sw new file mode 100644 index 00000000000..898bbe8b3f2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/src/foo.sw @@ -0,0 +1,6 @@ +library foo; + +pub enum Foo { + A: (), + B: (), +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/src/main.sw new file mode 100644 index 00000000000..da4d04e4f00 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/src/main.sw @@ -0,0 +1,21 @@ +script; + +dep foo; + +struct Bar { + baz: ::foo::Foo +} + + +fn main() { + let x = Bar { + baz: ::foo::Foo::A + }; + + let b = match x { + Bar { baz: ::foo::Foo::A(_) } => true, + _ => false, + }; + + assert(b); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/test.toml new file mode 100644 index 00000000000..44ca8ea93c4 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath2/test.toml @@ -0,0 +1,3 @@ +category = "run" +expected_result = { action = "return", value = 0 } +validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/Forc.lock new file mode 100644 index 00000000000..c71b4eef306 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-0D225CDF4C64C2FD' + +[[package]] +name = 'std' +source = 'path+from-root-0D225CDF4C64C2FD' +dependencies = ['core'] + +[[package]] +name = 'typeinfo_custom_callpath_with_import' +source = 'member' +dependencies = ['std'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/Forc.toml new file mode 100644 index 00000000000..e23c72b9ff2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "typeinfo_custom_callpath_with_import" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/json_abi_oracle.json new file mode 100644 index 00000000000..fad72a08f17 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": [], + "type": "()", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/src/foo.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/src/foo.sw new file mode 100644 index 00000000000..898bbe8b3f2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/src/foo.sw @@ -0,0 +1,6 @@ +library foo; + +pub enum Foo { + A: (), + B: (), +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/src/main.sw new file mode 100644 index 00000000000..e562f1b2155 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/src/main.sw @@ -0,0 +1,24 @@ +script; + +dep foo; + +use foo::*; + +struct Bar { + baz1: foo::Foo, + baz2: Foo, +} + +fn main() { + let x = Bar { + baz1: Foo::A, + baz2: foo::Foo::A, + }; + + let b = match x { + Bar { baz1: ::foo::Foo::A(_), baz2: Foo::A(_) } => true, + _ => false, + }; + + assert(b); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/test.toml new file mode 100644 index 00000000000..44ca8ea93c4 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/typeinfo_custom_callpath_with_import/test.toml @@ -0,0 +1,3 @@ +category = "run" +expected_result = { action = "return", value = 0 } +validate_abi = true