Skip to content

Commit

Permalink
Adds fully qualified paths for methods. (FuelLabs#4579)
Browse files Browse the repository at this point in the history
## Description

With the changes in this PR it is now possible to qualify a trait to
disambiguate the method to be used, such as `<S as Trait>::method()`.

Fixes FuelLabs#4383
Fixes FuelLabs#4025

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [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.

---------

Co-authored-by: IGI-111 <[email protected]>
  • Loading branch information
esdrubal and IGI-111 authored May 31, 2023
1 parent 99fb86f commit 1f93a2f
Show file tree
Hide file tree
Showing 33 changed files with 695 additions and 32 deletions.
10 changes: 9 additions & 1 deletion sway-core/src/language/parsed/expression/method_name.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::language::CallPath;
use crate::type_system::TypeBinding;
use crate::{Ident, TypeInfo};
use crate::{Ident, TypeArgument, TypeInfo};

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone)]
Expand All @@ -20,6 +20,13 @@ pub enum MethodName {
/// used for things like core::ops::add(a, b).
/// in this case, the first argument determines the type to look for
FromTrait { call_path: CallPath },
/// Represents a method lookup with a fully qualified path.
/// like <S as Trait>::method()
FromQualifiedPathRoot {
ty: TypeArgument,
as_trait: TypeInfo,
method_name: Ident,
},
}

impl MethodName {
Expand All @@ -29,6 +36,7 @@ impl MethodName {
MethodName::FromType { method_name, .. } => method_name.clone(),
MethodName::FromTrait { call_path, .. } => call_path.suffix.clone(),
MethodName::FromModule { method_name, .. } => method_name.clone(),
MethodName::FromQualifiedPathRoot { method_name, .. } => method_name.clone(),
}
}
}
9 changes: 9 additions & 0 deletions sway-core/src/language/parsed/expression/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
language::{parsed::CodeBlock, *},
type_system::TypeBinding,
TypeArgument, TypeInfo,
};
use sway_types::{ident::Ident, Span, Spanned};

Expand Down Expand Up @@ -103,8 +104,16 @@ impl Spanned for AmbiguousSuffix {
}
}

#[derive(Debug, Clone)]
pub struct QualifiedPathRootTypes {
pub ty: TypeArgument,
pub as_trait: TypeInfo,
pub as_trait_span: Span,
}

#[derive(Debug, Clone)]
pub struct AmbiguousPathExpression {
pub qualified_path_root: Option<QualifiedPathRootTypes>,
pub call_path_binding: TypeBinding<CallPath<AmbiguousSuffix>>,
pub args: Vec<Expression>,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,15 @@ impl ty::TyExpression {
let AmbiguousPathExpression {
call_path_binding,
args,
qualified_path_root,
} = *e;
Self::type_check_ambiguous_path(ctx.by_ref(), call_path_binding, span, args)
Self::type_check_ambiguous_path(
ctx.by_ref(),
call_path_binding,
span,
args,
qualified_path_root,
)
}
ExpressionKind::DelineatedPath(delineated_path_expression) => {
let DelineatedPathExpression {
Expand Down Expand Up @@ -1036,9 +1043,42 @@ impl ty::TyExpression {
}: TypeBinding<CallPath<AmbiguousSuffix>>,
span: Span,
args: Vec<Expression>,
qualified_path_root: Option<QualifiedPathRootTypes>,
) -> CompileResult<ty::TyExpression> {
let decl_engine = ctx.decl_engine;

if let Some(QualifiedPathRootTypes { ty, as_trait, .. }) = qualified_path_root {
if !prefixes.is_empty() || before.is_some() {
return err(
vec![],
vec![
ConvertParseTreeError::UnexpectedCallPathPrefixAfterQualifiedRoot {
span: path_span,
}
.into(),
],
);
}

let method_name_binding = TypeBinding {
inner: MethodName::FromQualifiedPathRoot {
ty,
as_trait,
method_name: suffix,
},
type_arguments,
span: path_span,
};

return type_check_method_application(
ctx.by_ref(),
method_name_binding,
Vec::new(),
args,
span,
);
}

// is it a singleton?
let before = if let Some(b) = before {
b
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ pub(crate) fn type_check_method_application(
is_absolute: false,
},
MethodName::FromTrait { call_path } => call_path,
MethodName::FromQualifiedPathRoot { method_name, .. } => CallPath {
prefixes: vec![],
suffix: method_name,
is_absolute: false,
},
};

// build the function selector
Expand Down Expand Up @@ -463,7 +468,9 @@ pub(crate) fn resolve_method_name(
&type_info_prefix,
method_name,
ctx.self_type(),
ctx.type_annotation(),
&arguments,
None,
engines,
),
return err(warnings, errors),
Expand All @@ -490,7 +497,9 @@ pub(crate) fn resolve_method_name(
&module_path,
&call_path.suffix,
ctx.self_type(),
ctx.type_annotation(),
&arguments,
None,
engines,
),
return err(warnings, errors),
Expand All @@ -517,14 +526,44 @@ pub(crate) fn resolve_method_name(
&module_path,
method_name,
ctx.self_type(),
ctx.type_annotation(),
&arguments,
None,
engines,
),
return err(warnings, errors),
warnings,
errors
);

(decl_ref, type_id)
}
MethodName::FromQualifiedPathRoot {
ty,
as_trait,
method_name,
} => {
// type check the call path
let type_id = ty.type_id;
let type_info_prefix = vec![];

// find the method
let decl_ref = check!(
ctx.namespace.find_method_for_type(
type_id,
&type_info_prefix,
method_name,
ctx.self_type(),
ctx.type_annotation(),
&arguments,
Some(as_trait.clone()),
engines
),
return err(warnings, errors),
warnings,
errors
);

(decl_ref, type_id)
}
};
Expand Down
Loading

0 comments on commit 1f93a2f

Please sign in to comment.