Skip to content

const generics for standalone fns #7175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ impl<'eng> FnCompiler<'eng> {
)
} else {
let function_decl = self.engines.de().get_function(fn_ref);

self.compile_fn_call(
context,
md_mgr,
Expand Down
77 changes: 62 additions & 15 deletions sway-core/src/language/ty/declaration/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
type_system::*,
types::*,
};
use ast_elements::type_parameter::ConstGenericExpr;
use monomorphization::MonomorphizeHelper;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
Expand Down Expand Up @@ -74,14 +75,18 @@ impl DebugWithEngines for TyFunctionDecl {
self.type_parameters
.iter()
.map(|p| {
let p = p
.as_type_parameter()
.expect("only works for type parameters");
format!(
"{:?} -> {:?}",
engines.help_out(p.initial_type_id),
engines.help_out(p.type_id)
)
match p {
TypeParameter::Type(p) => {
format!(
"{:?} -> {:?}",
engines.help_out(p.initial_type_id),
engines.help_out(p.type_id)
)
}
TypeParameter::Const(p) => {
format!("{} -> {:?}", p.name, p.expr)
}
}
})
.collect::<Vec<_>>()
.join(", ")
Expand Down Expand Up @@ -150,6 +155,19 @@ impl MaterializeConstGenerics for TyFunctionDecl {
name: &str,
value: &TyExpression,
) -> Result<(), ErrorEmitted> {
for tp in self.type_parameters.iter_mut() {
match tp {
TypeParameter::Type(p) => p
.type_id
.materialize_const_generics(engines, handler, name, value)?,
TypeParameter::Const(p) if p.name.as_str() == name => {
assert!(p.expr.is_none());
p.expr = Some(ConstGenericExpr::from_ty_expression(handler, value)?);
}
_ => {}
}
}

for param in self.parameters.iter_mut() {
param
.type_argument
Expand Down Expand Up @@ -666,11 +684,17 @@ impl TyFunctionParameter {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum TyFunctionSigTypeParameter {
Type(TypeId),
Const(ConstGenericExpr),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TyFunctionSig {
pub return_type: TypeId,
pub parameters: Vec<TypeId>,
pub type_parameters: Vec<TypeId>,
pub type_parameters: Vec<TyFunctionSigTypeParameter>,
}

impl DisplayWithEngines for TyFunctionSig {
Expand All @@ -688,7 +712,11 @@ impl DebugWithEngines for TyFunctionSig {
"<{}>",
self.type_parameters
.iter()
.map(|p| format!("{}", engines.help_out(p)))
.map(|p| match p {
TyFunctionSigTypeParameter::Type(t) => format!("{:?}", engines.help_out(t)),
TyFunctionSigTypeParameter::Const(expr) =>
format!("{:?}", engines.help_out(expr)),
})
.collect::<Vec<_>>()
.join(", "),
)
Expand Down Expand Up @@ -719,9 +747,16 @@ impl TyFunctionSig {
type_parameters: fn_decl
.type_parameters
.iter()
.filter_map(|x| x.as_type_parameter())
.map(|p| p.type_id)
.collect::<Vec<_>>(),
.map(|x| match x {
TypeParameter::Type(p) => TyFunctionSigTypeParameter::Type(p.type_id),
TypeParameter::Const(p) => {
let expr = ConstGenericExpr::AmbiguousVariableExpression {
ident: p.name.clone(),
};
TyFunctionSigTypeParameter::Const(p.expr.clone().unwrap_or(expr))
}
})
.collect(),
}
}

Expand All @@ -735,7 +770,11 @@ impl TyFunctionSig {
&& self
.type_parameters
.iter()
.all(|p| p.is_concrete(engines, TreatNumericAs::Concrete))
.filter_map(|x| match x {
TyFunctionSigTypeParameter::Type(type_id) => Some(type_id),
TyFunctionSigTypeParameter::Const(_) => None,
})
.all(|type_id| type_id.is_concrete(engines, TreatNumericAs::Concrete))
}

/// Returns a String representing the function.
Expand All @@ -749,7 +788,15 @@ impl TyFunctionSig {
"<{}>",
self.type_parameters
.iter()
.map(|p| p.get_type_str(engines))
.map(|x| match x {
TyFunctionSigTypeParameter::Type(type_id) => type_id.get_type_str(engines),
TyFunctionSigTypeParameter::Const(p) => {
match p {
ConstGenericExpr::Literal { val, .. } => val.to_string(),
ConstGenericExpr::AmbiguousVariableExpression { .. } => todo!(),
}
}
})
.collect::<Vec<_>>()
.join(", "),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ use sway_error::{
use symbol_collection_context::SymbolCollectionContext;

use crate::{
decl_engine::{parsed_id::ParsedDeclId, DeclId, DeclRefFunction},
decl_engine::{
parsed_id::ParsedDeclId, DeclEngineInsert as _, DeclId, DeclRefFunction,
ParsedDeclEngineGet as _,
},
language::{
parsed::*,
ty::{self, TyCodeBlock, TyFunctionDecl},
CallPath, Visibility,
ty::{self, ConstGenericDecl, TyCodeBlock, TyConstGenericDecl, TyDecl, TyFunctionDecl},
CallPath, CallPathType, Visibility,
},
semantic_analysis::*,
type_system::*,
Expand All @@ -34,6 +37,22 @@ impl ty::TyFunctionDecl {

// create a namespace for the function
let _ = ctx.scoped(engines, fn_decl.span.clone(), Some(decl), |scoped_ctx| {
let const_generic_parameters = fn_decl
.type_parameters
.iter()
.filter_map(|x| x.as_const_parameter())
.filter_map(|x| x.id.as_ref());

for const_generic_parameter in const_generic_parameters {
let const_generic_decl = engines.pe().get(const_generic_parameter);
scoped_ctx.insert_parsed_symbol(
handler,
engines,
const_generic_decl.name.clone(),
Declaration::ConstGenericDeclaration(*const_generic_parameter),
)?;
}

TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body)
});
Ok(())
Expand Down Expand Up @@ -114,6 +133,36 @@ impl ty::TyFunctionDecl {
None,
)?;

// const generic parameters
let const_generic_parameters = type_parameters
.iter()
.filter_map(|x| x.as_const_parameter())
.filter_map(|x| x.id.as_ref());
for const_generic_decl_id in const_generic_parameters {
let const_generic_decl = ctx.engines.pe().get(const_generic_decl_id);
let decl_ref = ctx.engines.de().insert(
TyConstGenericDecl {
call_path: CallPath {
prefixes: vec![],
suffix: const_generic_decl.name.clone(),
callpath_type: CallPathType::Ambiguous,
},
span: const_generic_decl.span.clone(),
return_type: const_generic_decl.ty,
value: None,
},
Some(const_generic_decl_id),
);

ctx.insert_symbol(
handler,
const_generic_decl.name.clone(),
TyDecl::ConstGenericDecl(ConstGenericDecl {
decl_id: *decl_ref.id(),
}),
)?;
}

// type check the function parameters, which will also insert them into the namespace
let mut new_parameters = vec![];
handler.scope(|handler| {
Expand Down Expand Up @@ -212,10 +261,10 @@ impl ty::TyFunctionDecl {

// Insert the previously type checked type parameters into the current namespace.
// We insert all type parameter before the constraints because some constraints may depend on the parameters.
for p in type_parameters.iter().filter_map(|x| x.as_type_parameter()) {
for p in type_parameters.iter() {
p.insert_into_namespace_self(handler, ctx.by_ref())?;
}
for p in type_parameters.iter().filter_map(|x| x.as_type_parameter()) {
for p in type_parameters.iter() {
p.insert_into_namespace_constraints(handler, ctx.by_ref())?;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ pub(crate) fn instantiate_function_application(
function_decl.name.as_str(),
&call_path_binding.span(),
)?;

function_decl.replace_decls(&decl_mapping, handler, &mut ctx)?;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,7 @@ pub(crate) fn struct_instantiation(
.scoped(handler, None, |scoped_ctx| {
// Insert struct type parameter into namespace.
// This is required so check_type_parameter_bounds can resolve generic trait type parameters.
for p in struct_decl
.generic_parameters
.iter()
.filter_map(|x| x.as_type_parameter())
{
for p in struct_decl.generic_parameters.iter() {
p.insert_into_namespace_self(handler, scoped_ctx.by_ref())?;
}

Expand Down
15 changes: 14 additions & 1 deletion sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ pub fn item_fn_to_function_declaration(
let kind = override_kind.unwrap_or(kind);
let implementing_type = context.implementing_type.clone();

let generic_parameters = generic_params_opt_to_type_parameters_with_parent(
let mut generic_parameters = generic_params_opt_to_type_parameters_with_parent(
context,
handler,
engines,
Expand All @@ -571,6 +571,19 @@ pub fn item_fn_to_function_declaration(
parent_where_clause_opt,
)?;

for p in generic_parameters.iter_mut() {
match p {
TypeParameter::Type(_) => {}
TypeParameter::Const(p) => {
p.id = Some(engines.pe().insert(ConstGenericDeclaration {
name: p.name.clone(),
ty: p.ty,
span: p.span.clone(),
}));
}
}
}

let fn_decl = FunctionDeclaration {
purity: attributes.purity(),
attributes,
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/type_system/ast_elements/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ impl TypeCheckTypeBinding<ty::TyFunctionDecl> for TypeBinding<CallPath> {
let fn_ref = unknown_decl.to_fn_ref(handler, ctx.engines())?;
// Get a new copy from the declaration engine.
let mut new_copy = (*decl_engine.get_function(fn_ref.id())).clone();

match self.type_arguments {
// Monomorphize the copy, in place.
TypeArgs::Regular(_) => {
Expand Down Expand Up @@ -352,6 +353,7 @@ impl TypeCheckTypeBinding<ty::TyFunctionDecl> for TypeBinding<CallPath> {
decl_engine.get_parsed_decl_id(fn_ref.id()).as_ref(),
)
.with_parent(ctx.engines.de(), fn_ref.id().into());

Ok((new_fn_ref, None, None))
}
}
Expand Down
Loading
Loading