Skip to content

Commit aa126d6

Browse files
authored
Fully resolve trait constraints call paths. (#6962)
## Description Fully resolves trait constraints call paths. To be used in trait coherence work. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers.
1 parent 3d8eeba commit aa126d6

File tree

14 files changed

+188
-108
lines changed

14 files changed

+188
-108
lines changed

sway-core/src/language/call_path.rs

+37-2
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,14 @@ impl<T: Spanned> Spanned for CallPath<T> {
309309
}
310310
}
311311

312+
/// This controls the type of display type for call path display string conversions.
313+
pub enum CallPathDisplayType {
314+
/// Prints the regular call path as exists internally.
315+
Regular,
316+
/// Strips the current root package if it exists as prefix.
317+
StripPackagePrefix,
318+
}
319+
312320
impl CallPath {
313321
pub fn fullpath(path: &[&str]) -> Self {
314322
assert!(!path.is_empty());
@@ -398,6 +406,27 @@ impl CallPath {
398406
converted
399407
}
400408

409+
pub fn to_display_path(
410+
&self,
411+
display_type: CallPathDisplayType,
412+
namespace: &Namespace,
413+
) -> CallPath {
414+
let mut display_path = self.clone();
415+
416+
match display_type {
417+
CallPathDisplayType::Regular => {}
418+
CallPathDisplayType::StripPackagePrefix => {
419+
if let Some(first) = self.prefixes.first() {
420+
if namespace.root_ref().current_package_root_module().name() == first {
421+
display_path = display_path.lshift();
422+
}
423+
}
424+
}
425+
};
426+
427+
display_path
428+
}
429+
401430
/// Create a string form of the given [CallPath] and zero or more [TypeArgument]s.
402431
/// The returned string is convenient for displaying full names, including generic arguments, in help messages.
403432
/// E.g.:
@@ -553,11 +582,17 @@ impl CallPath {
553582
Some(module) => {
554583
// Resolve the path suffix in the found module
555584
match module.resolve_symbol(&Handler::default(), engines, &full_path.suffix) {
556-
Ok((_, decl_path)) => {
585+
Ok((decl, decl_path)) => {
586+
let name = decl.expect_typed().get_name(engines);
587+
let suffix = if name.as_str() != full_path.suffix.as_str() {
588+
name
589+
} else {
590+
full_path.suffix
591+
};
557592
// Replace the resolvable path with the declaration's path
558593
CallPath {
559594
prefixes: decl_path,
560-
suffix: full_path.suffix.clone(),
595+
suffix,
561596
callpath_type: full_path.callpath_type,
562597
}
563598
}

sway-core/src/language/ty/declaration/declaration.rs

+61-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use sway_error::{
1515
error::CompileError,
1616
handler::{ErrorEmitted, Handler},
1717
};
18-
use sway_types::{Ident, Named, Span, Spanned};
18+
use sway_types::{BaseIdent, Ident, Named, Span, Spanned};
1919

2020
#[derive(Clone, Debug, Serialize, Deserialize)]
2121
pub enum TyDecl {
@@ -667,6 +667,66 @@ impl TyDecl {
667667
}
668668
}
669669

670+
pub fn get_name(&self, engines: &Engines) -> BaseIdent {
671+
match self {
672+
TyDecl::VariableDecl(ty_variable_decl) => ty_variable_decl.name.clone(),
673+
TyDecl::ConstantDecl(constant_decl) => engines
674+
.de()
675+
.get_constant(&constant_decl.decl_id)
676+
.call_path
677+
.suffix
678+
.clone(),
679+
TyDecl::ConfigurableDecl(configurable_decl) => engines
680+
.de()
681+
.get_configurable(&configurable_decl.decl_id)
682+
.call_path
683+
.suffix
684+
.clone(),
685+
TyDecl::TraitTypeDecl(trait_type_decl) => {
686+
engines.de().get_type(&trait_type_decl.decl_id).name.clone()
687+
}
688+
TyDecl::FunctionDecl(function_decl) => engines
689+
.de()
690+
.get_function(&function_decl.decl_id)
691+
.name
692+
.clone(),
693+
TyDecl::TraitDecl(trait_decl) => {
694+
engines.de().get_trait(&trait_decl.decl_id).name.clone()
695+
}
696+
TyDecl::StructDecl(struct_decl) => engines
697+
.de()
698+
.get_struct(&struct_decl.decl_id)
699+
.call_path
700+
.suffix
701+
.clone(),
702+
TyDecl::EnumDecl(enum_decl) => engines
703+
.de()
704+
.get_enum(&enum_decl.decl_id)
705+
.call_path
706+
.suffix
707+
.clone(),
708+
TyDecl::EnumVariantDecl(_enum_variant_decl) => {
709+
unreachable!()
710+
}
711+
TyDecl::ImplSelfOrTrait(impl_self_or_trait) => engines
712+
.de()
713+
.get_impl_self_or_trait(&impl_self_or_trait.decl_id)
714+
.trait_name
715+
.suffix
716+
.clone(),
717+
TyDecl::AbiDecl(abi_decl) => engines.de().get_abi(&abi_decl.decl_id).name.clone(),
718+
TyDecl::GenericTypeForFunctionScope(_generic_type_for_function_scope) => unreachable!(),
719+
TyDecl::ErrorRecovery(_span, _error_emitted) => unreachable!(),
720+
TyDecl::StorageDecl(_storage_decl) => unreachable!(),
721+
TyDecl::TypeAliasDecl(type_alias_decl) => engines
722+
.de()
723+
.get_type_alias(&type_alias_decl.decl_id)
724+
.call_path
725+
.suffix
726+
.clone(),
727+
}
728+
}
729+
670730
/// Friendly name string used for error reporting,
671731
/// which consists of the identifier for the declaration.
672732
pub fn friendly_name(&self, engines: &Engines) -> String {

sway-core/src/type_system/ast_elements/trait_constraint.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use crate::{
22
engine_threading::*,
3-
language::{parsed::Supertrait, ty, CallPath},
3+
language::{parsed::Supertrait, ty, CallPath, CallPathDisplayType},
44
semantic_analysis::{
55
declaration::{insert_supertraits_into_namespace, SupertraitOf},
66
TypeCheckContext,
77
},
88
type_system::priv_prelude::*,
99
types::{CollectTypesMetadata, CollectTypesMetadataContext, TypeMetadata},
10-
EnforceTypeArguments,
10+
EnforceTypeArguments, Namespace,
1111
};
1212
use serde::{Deserialize, Serialize};
1313
use std::{
@@ -159,6 +159,10 @@ impl TraitConstraint {
159159
}));
160160
}
161161

162+
self.trait_name = self
163+
.trait_name
164+
.to_canonical_path(ctx.engines(), ctx.namespace());
165+
162166
// Type check the type arguments.
163167
for type_argument in &mut self.type_arguments {
164168
type_argument.type_id = ctx
@@ -259,4 +263,11 @@ impl TraitConstraint {
259263

260264
Ok(())
261265
}
266+
267+
pub fn to_display_name(&self, engines: &Engines, namespace: &Namespace) -> String {
268+
let display_path = self
269+
.trait_name
270+
.to_display_path(CallPathDisplayType::StripPackagePrefix, namespace);
271+
display_path.to_string_with_args(engines, &self.type_arguments)
272+
}
262273
}

sway-core/src/type_system/ast_elements/type_parameter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ impl TypeParameter {
558558
return Err(handler.emit_err(CompileError::MultipleImplsSatisfyingTraitForType{
559559
span:access_span.clone(),
560560
type_annotation: engines.help_out(type_id).to_string(),
561-
trait_names: trait_constraints.iter().map(|t| engines.help_out(t).to_string()).collect(),
561+
trait_names: trait_constraints.iter().map(|t| t.to_display_name(engines, ctx.namespace())).collect(),
562562
trait_types_and_names: concrete_trait_type_ids.iter().map(|t| (engines.help_out(t.0).to_string(), t.1.clone())).collect::<Vec<_>>()
563563
}));
564564
}

test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/aliases/test.toml

+35-4
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,40 @@ category = "fail"
9393
#check: $()impl Items2Trait<TestStruct2> for TestStruct1 {
9494
#nextln: $()Trait "Items2Trait" cannot be found in the current scope.
9595

96+
#check: $()error
97+
#check: $()fn project_items_3_struct(input: Items3_Struct) -> u64 {
98+
#nextln: $()Could not find symbol "Items3_Struct" in this scope.
99+
100+
#check: $()error
101+
#check: $()fn project_items_3_struct(input: Items3_Struct) -> u64 {
102+
#nextln: $()Unknown type name "Items3_Struct".
103+
104+
#check: $()error
105+
#check: $()fn project_items_3_enum(input: Items3_Enum) -> u64 {
106+
#nextln: $()Could not find symbol "Items3_Enum" in this scope.
107+
108+
#check: $()error
109+
#check: $()fn project_items_3_enum(input: Items3_Enum) -> u64 {
110+
#nextln: $()Unknown type name "Items3_Enum".
111+
112+
#check: $()error
113+
#check: $()fn project_items_3_variants(input: Items3_Variants) -> u64 {
114+
#check: $()Could not find symbol "Items3_U" in this scope.
115+
116+
#check: $()error
117+
#check: $()Could not find symbol "Items3_V" in this scope.
118+
119+
#check: $()error
120+
#check: $()fn call_items_3_function() -> u64 {
121+
#check: $()Could not find symbol "items_3_function" in this scope.
122+
123+
#check: $()error
124+
#check: $()impl Items3Trait<TestStruct2> for TestStruct1 {
125+
#check: $()Could not find symbol "Items3Trait" in this scope.
126+
127+
#check: $()Trait is already implemented for type
128+
#check: $()Trait "aliases::items_5::Items5Trait<TestStruct2>" is already implemented for type "TestStruct1".
129+
96130
#check: $()error
97131
#check: $()let items_2_struct = Items2_Struct { b: 123 };
98132
#nextln: $()Could not find symbol "Items2_Struct" in this scope.
@@ -181,8 +215,5 @@ category = "fail"
181215
#check: $()let items_3_trait_teststruct_1_res = teststruct_1.items_3_trait_function(teststruct_2);
182216
#nextln: $()No method "items_3_trait_function(TestStruct1, TestStruct2) -> bool" found for type "TestStruct1".
183217

184-
#check: $()error
185-
#check: $()let items_5_trait_teststruct_1_res = teststruct_1.items_5_trait_function(teststruct_2);
186-
#nextln: $()Multiple applicable items in scope.
218+
#check: $()Aborting due to 55 errors.
187219

188-
#check: $()Aborting due to 55 errors.

test/src/e2e_vm_tests/test_programs/should_fail/trait_cannot_find_in_scope_issue/src/main.sw

-29
This file was deleted.

test/src/e2e_vm_tests/test_programs/should_fail/trait_cannot_find_in_scope_issue/test.toml

-69
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
script;
2+
3+
pub mod lib;
4+
pub mod other_lib;
5+
mod trait_impls;
6+
7+
// Previously this was a `should_fail` test that checked if we emitted an error
8+
// related to the hash trait in sha256 trait constraint not being explicitly imported.
9+
10+
// After we changed trait constraints paths to be fully resolved, then lookup
11+
// of those types now works transparently even without the trait being imported here.
12+
13+
// In fact the previous behavior was problematic since a locally defined trait with the
14+
// same name would take precedence, thus making trait constraint type lookups in essen
15+
// dynamically scoped.
16+
17+
use std::hash::sha256;
18+
19+
use ::lib::{S, A, function};
20+
use ::trait_impls::*;
21+
22+
fn main() {
23+
let _ = sha256(123u8);
24+
25+
let s = S {};
26+
s.method_01(0u8);
27+
s.method_02(A {});
28+
S::associated_function(A {});
29+
30+
function(A {});
31+
32+
let a = A {};
33+
34+
a.trait_method(A {});
35+
36+
A::trait_associated_function(A {});
37+
38+
function_with_duplicated_trait(A {});
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
category = "compile"
2+
expected_warnings = 10

0 commit comments

Comments
 (0)