Skip to content

Commit

Permalink
Merge de88bbd into e3eb823
Browse files Browse the repository at this point in the history
  • Loading branch information
esdrubal committed Jun 13, 2024
2 parents e3eb823 + de88bbd commit 85f8bf6
Show file tree
Hide file tree
Showing 10 changed files with 397 additions and 58 deletions.
8 changes: 8 additions & 0 deletions sway-core/src/ir_generation/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ fn compile_fn(
purity,
span,
is_trait_method_dummy,
is_type_check_finalized,
..
} = ast_fn_decl;

Expand All @@ -500,6 +501,13 @@ fn compile_fn(
)]);
}

if !*is_type_check_finalized {
return Err(vec![CompileError::InternalOwned(
format!("Method {name} did not finalize type checking phase."),
span.clone(),
)]);
}

let args = ast_fn_decl
.parameters
.iter()
Expand Down
77 changes: 77 additions & 0 deletions sway-core/src/language/ty/declaration/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub struct TyFunctionDecl {
pub purity: Purity,
pub where_clause: Vec<(Ident, Vec<TraitConstraint>)>,
pub is_trait_method_dummy: bool,
pub is_type_check_finalized: bool,
pub kind: TyFunctionDeclKind,
}

Expand Down Expand Up @@ -182,6 +183,7 @@ impl HashWithEngines for TyFunctionDecl {
implementing_for_typeid: _,
where_clause: _,
is_trait_method_dummy: _,
is_type_check_finalized: _,
kind: _,
} = self;
name.hash(state);
Expand Down Expand Up @@ -341,6 +343,7 @@ impl TyFunctionDecl {
type_parameters: Default::default(),
where_clause: where_clause.clone(),
is_trait_method_dummy: false,
is_type_check_finalized: true,
kind: match kind {
FunctionDeclarationKind::Default => TyFunctionDeclKind::Default,
FunctionDeclarationKind::Entry => TyFunctionDeclKind::Entry,
Expand Down Expand Up @@ -544,6 +547,41 @@ impl TyFunctionParameter {
pub struct TyFunctionSig {
pub return_type: TypeId,
pub parameters: Vec<TypeId>,
pub type_parameters: Vec<TypeId>,
}

impl DisplayWithEngines for TyFunctionSig {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
write!(f, "{:?}", engines.help_out(self))
}
}

impl DebugWithEngines for TyFunctionSig {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
let tp_str = if self.type_parameters.is_empty() {
"".to_string()
} else {
format!(
"<{}>",
self.type_parameters
.iter()
.map(|p| format!("{}", engines.help_out(p)))
.collect::<Vec<_>>()
.join(", "),
)
};
write!(
f,
"fn{}({}) -> {}",
tp_str,
self.parameters
.iter()
.map(|p| format!("{}", engines.help_out(p)))
.collect::<Vec<_>>()
.join(", "),
engines.help_out(self.return_type),
)
}
}

impl TyFunctionSig {
Expand All @@ -555,6 +593,45 @@ impl TyFunctionSig {
.iter()
.map(|p| p.type_argument.type_id)
.collect::<Vec<_>>(),
type_parameters: fn_decl
.type_parameters
.iter()
.map(|p| p.type_id)
.collect::<Vec<_>>(),
}
}

pub fn is_concrete(&self, engines: &Engines) -> bool {
self.return_type.is_concrete(engines)
&& self.parameters.iter().all(|p| p.is_concrete(engines))
&& self.type_parameters.iter().all(|p| p.is_concrete(engines))
}

/// Returns a String representing the function.
/// When the function is monomorphized the returned String is unique.
/// Two monomorphized functions that generate the same String can be assumed to be the same.
pub fn get_type_str(&self, engines: &Engines) -> String {
let tp_str = if self.type_parameters.is_empty() {
"".to_string()
} else {
format!(
"<{}>",
self.type_parameters
.iter()
.map(|p| p.get_type_str(engines))
.collect::<Vec<_>>()
.join(", "),
)
};
format!(
"fn{}({}) -> {}",
tp_str,
self.parameters
.iter()
.map(|p| p.get_type_str(engines))
.collect::<Vec<_>>()
.join(", "),
self.return_type.get_type_str(engines),
)
}
}
39 changes: 38 additions & 1 deletion sway-core/src/query_engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use parking_lot::RwLock;
use std::{collections::HashMap, path::PathBuf, sync::Arc, time::SystemTime};
use sway_error::error::CompileError;
use sway_error::warning::CompileWarning;
use sway_types::IdentUnique;

use crate::Programs;
use crate::decl_engine::{DeclId, DeclRef};
use crate::language::ty::{TyFunctionDecl, TyFunctionSig};
use crate::{Engines, Programs};

pub type ModulePath = Arc<PathBuf>;

Expand Down Expand Up @@ -43,11 +46,19 @@ pub struct ProgramsCacheEntry {

pub type ProgramsCacheMap = HashMap<Arc<PathBuf>, ProgramsCacheEntry>;

#[derive(Clone, Debug)]
pub struct FunctionCacheEntry {
pub fn_decl: DeclRef<DeclId<TyFunctionDecl>>,
}

pub type FunctionsCacheMap = HashMap<(IdentUnique, String), FunctionCacheEntry>;

#[derive(Debug, Default, Clone)]
pub struct QueryEngine {
// We want the below types wrapped in Arcs to optimize cloning from LSP.
parse_module_cache: Arc<RwLock<ModuleCacheMap>>,
programs_cache: Arc<RwLock<ProgramsCacheMap>>,
function_cache: Arc<RwLock<FunctionsCacheMap>>,
}

impl QueryEngine {
Expand All @@ -73,4 +84,30 @@ impl QueryEngine {
let mut cache = self.programs_cache.write();
cache.insert(entry.path.clone(), entry);
}

pub fn get_function(
&self,
engines: &Engines,
ident: IdentUnique,
sig: TyFunctionSig,
) -> Option<DeclRef<DeclId<TyFunctionDecl>>> {
let cache = self.function_cache.read();
cache
.get(&(ident, sig.get_type_str(engines)))
.map(|s| s.fn_decl.clone())
}

pub fn insert_function(
&self,
engines: &Engines,
ident: IdentUnique,
sig: TyFunctionSig,
fn_decl: DeclRef<DeclId<TyFunctionDecl>>,
) {
let mut cache = self.function_cache.write();
cache.insert(
(ident, sig.get_type_str(engines)),
FunctionCacheEntry { fn_decl },
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ impl ty::TyFunctionDecl {
purity: *purity,
where_clause: where_clause.clone(),
is_trait_method_dummy: false,
is_type_check_finalized: false,
kind: match kind {
FunctionDeclarationKind::Default => ty::TyFunctionDeclKind::Default,
FunctionDeclarationKind::Entry => ty::TyFunctionDeclKind::Entry,
Expand Down Expand Up @@ -222,6 +223,7 @@ impl ty::TyFunctionDecl {
.unwrap_or_else(|_err| ty::TyCodeBlock::default());

ty_fn_decl.body = body;
ty_fn_decl.is_type_check_finalized = true;

return_type.type_id.check_type_parameter_bounds(
handler,
Expand Down Expand Up @@ -324,6 +326,7 @@ fn test_function_selector_behavior() {
is_contract_call: false,
where_clause: vec![],
is_trait_method_dummy: false,
is_type_check_finalized: true,
kind: ty::TyFunctionDeclKind::Default,
};

Expand Down Expand Up @@ -384,6 +387,7 @@ fn test_function_selector_behavior() {
is_contract_call: false,
where_clause: vec![],
is_trait_method_dummy: false,
is_type_check_finalized: true,
kind: ty::TyFunctionDeclKind::Default,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ impl ty::TyTraitFn {
is_contract_call: matches!(abi_mode, AbiMode::ImplAbiFn(..)),
where_clause: vec![],
is_trait_method_dummy: true,
is_type_check_finalized: true,
kind: ty::TyFunctionDeclKind::Default,
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use crate::{
decl_engine::{DeclEngineInsert, DeclRefFunction, ReplaceDecls},
language::{ty, *},
language::{
ty::{self, TyFunctionSig},
*,
},
semantic_analysis::{ast_node::*, TypeCheckContext},
};
use indexmap::IndexMap;
use sway_error::error::CompileError;
use sway_types::Spanned;
use sway_types::{IdentUnique, Spanned};

const UNIFY_ARGS_HELP_TEXT: &str =
"The argument that has been provided to this function's type does \
Expand All @@ -21,7 +24,8 @@ pub(crate) fn instantiate_function_application(
arguments: Option<&[Expression]>,
span: Span,
) -> Result<ty::TyExpression, ErrorEmitted> {
let decl_engine = ctx.engines.de();
let engines = ctx.engines();
let decl_engine = engines.de();

let mut function_decl = (*decl_engine.get_function(&function_decl_ref)).clone();

Expand Down Expand Up @@ -62,22 +66,50 @@ pub(crate) fn instantiate_function_application(
&function_decl.parameters,
)?;

// Handle the trait constraints. This includes checking to see if the trait
// constraints are satisfied and replacing old decl ids based on the
// constraint with new decl ids based on the new type.
let decl_mapping = TypeParameter::gather_decl_mapping_from_trait_constraints(
handler,
ctx.by_ref(),
&function_decl.type_parameters,
function_decl.name.as_str(),
&call_path_binding.span(),
)?;
let mut function_return_type_id = function_decl.return_type.type_id;

let function_ident: IdentUnique = function_decl.name.clone().into();
let function_sig = TyFunctionSig::from_fn_decl(&function_decl);

function_decl.replace_decls(&decl_mapping, handler, &mut ctx)?;
let return_type = function_decl.return_type.clone();
let new_decl_ref = decl_engine
.insert(function_decl)
.with_parent(decl_engine, (*function_decl_ref.id()).into());
let new_decl_ref = if let Some(cached_fn_ref) =
ctx.engines()
.qe()
.get_function(engines, function_ident.clone(), function_sig.clone())
{
cached_fn_ref
} else {
// Handle the trait constraints. This includes checking to see if the trait
// constraints are satisfied and replacing old decl ids based on the
// constraint with new decl ids based on the new type.
let decl_mapping = TypeParameter::gather_decl_mapping_from_trait_constraints(
handler,
ctx.by_ref(),
&function_decl.type_parameters,
function_decl.name.as_str(),
&call_path_binding.span(),
)?;

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

let method_sig = TyFunctionSig::from_fn_decl(&function_decl);

function_return_type_id = function_decl.return_type.type_id;
let function_is_type_check_finalized = function_decl.is_type_check_finalized;
let new_decl_ref = decl_engine
.insert(function_decl)
.with_parent(decl_engine, (*function_decl_ref.id()).into());

if method_sig.is_concrete(engines) && function_is_type_check_finalized {
ctx.engines().qe().insert_function(
engines,
function_ident,
method_sig,
new_decl_ref.clone(),
);
}

new_decl_ref
};

let exp = ty::TyExpression {
expression: ty::TyExpressionVariant::FunctionApplication {
Expand All @@ -91,7 +123,7 @@ pub(crate) fn instantiate_function_application(
contract_call_params: IndexMap::new(),
contract_caller: None,
},
return_type: return_type.type_id,
return_type: function_return_type_id,
span,
};

Expand Down
Loading

0 comments on commit 85f8bf6

Please sign in to comment.