From 032b7fb6e0a1526ea9d76793c74e8770bff73d8e Mon Sep 17 00:00:00 2001 From: Ori Ziv Date: Sun, 19 Nov 2023 17:22:43 +0200 Subject: [PATCH] Added indirect impl support for inference. Included small refactor + removal of unneed extra module lookup. --- crates/cairo-lang-semantic/src/db.rs | 1 + .../cairo-lang-semantic/src/expr/compute.rs | 24 +-------------- crates/cairo-lang-semantic/src/items/imp.rs | 23 +++++++++------ .../src/items/impl_alias.rs | 29 +++++++++++++++---- tests/bug_samples/indirect_impl_alias.cairo | 26 +++++++++++++++++ tests/bug_samples/lib.cairo | 1 + 6 files changed, 66 insertions(+), 38 deletions(-) create mode 100644 tests/bug_samples/indirect_impl_alias.cairo diff --git a/crates/cairo-lang-semantic/src/db.rs b/crates/cairo-lang-semantic/src/db.rs index c83a0e59f0f..0743329d5dd 100644 --- a/crates/cairo-lang-semantic/src/db.rs +++ b/crates/cairo-lang-semantic/src/db.rs @@ -268,6 +268,7 @@ pub trait SemanticGroup: /// Returns the impl definition pointed to by the impl alias, or an error if it points to /// something else. #[salsa::invoke(items::impl_alias::impl_alias_impl_def)] + #[salsa::cycle(items::impl_alias::impl_alias_impl_def_cycle)] fn impl_alias_impl_def(&self, impl_alias_id: ImplAliasId) -> Maybe; /// Private query to compute data about a type alias. #[salsa::invoke(items::impl_alias::priv_impl_alias_semantic_data)] diff --git a/crates/cairo-lang-semantic/src/expr/compute.rs b/crates/cairo-lang-semantic/src/expr/compute.rs index de6e1f2090c..ef4ddf5ed5e 100644 --- a/crates/cairo-lang-semantic/src/expr/compute.rs +++ b/crates/cairo-lang-semantic/src/expr/compute.rs @@ -606,28 +606,6 @@ fn compute_expr_function_call_semantic( ResolvedConcreteItem::Function(function) => { expr_function_call(ctx, function, named_args, syntax.stable_ptr().into()) } - ResolvedConcreteItem::TraitFunction(trait_function) => { - let impl_lookup_context = ctx.resolver.impl_lookup_context(); - let generic_function = ctx - .resolver - .inference() - .infer_trait_generic_function( - trait_function, - &impl_lookup_context, - Some(path.stable_ptr().untyped()), - ) - .map_err(|err| err.report(ctx.diagnostics, path.stable_ptr().untyped()))?; - let function_id = ctx - .resolver - .inference() - .infer_generic_function( - generic_function, - &impl_lookup_context, - Some(path.stable_ptr().untyped()), - ) - .map_err(|err| err.report(ctx.diagnostics, path.stable_ptr().untyped()))?; - expr_function_call(ctx, function_id, named_args, syntax.stable_ptr().into()) - } _ => Err(ctx.diagnostics.report( &path, UnexpectedElement { expected: vec![ElementKind::Function], actual: (&item).into() }, @@ -1070,7 +1048,7 @@ fn compute_method_function_call_data( candidate_traits, func_name.clone(), self_expr.stable_ptr().untyped(), - )?; + ); let trait_function_id = match candidates[..] { [] => { return Err(ctx diff --git a/crates/cairo-lang-semantic/src/items/imp.rs b/crates/cairo-lang-semantic/src/items/imp.rs index cb5234668b8..4ce52c28fbe 100644 --- a/crates/cairo-lang-semantic/src/items/imp.rs +++ b/crates/cairo-lang-semantic/src/items/imp.rs @@ -35,7 +35,7 @@ use super::functions::{ use super::generics::{semantic_generic_params, GenericArgumentHead, GenericParamsData}; use super::structure::SemanticStructEx; use super::trt::{ConcreteTraitGenericFunctionId, ConcreteTraitGenericFunctionLongId}; -use crate::corelib::{copy_trait, core_module, drop_trait}; +use crate::corelib::{copy_trait, drop_trait}; use crate::db::SemanticGroup; use crate::diagnostic::SemanticDiagnosticKind::{self, *}; use crate::diagnostic::{NotFoundItemType, SemanticDiagnostics}; @@ -720,8 +720,14 @@ pub fn module_impl_ids_for_trait_filter( uninferred_impls.push(UninferredImpl::ImplAlias(impl_alias_id)); } for use_id in db.module_uses_ids(module_id).unwrap_or_default().iter().copied() { - if let Ok(ResolvedGenericItem::Impl(impl_def_id)) = db.use_resolved_item(use_id) { - uninferred_impls.push(UninferredImpl::Def(impl_def_id)); + match db.use_resolved_item(use_id) { + Ok(ResolvedGenericItem::Impl(impl_def_id)) => { + uninferred_impls.push(UninferredImpl::Def(impl_def_id)); + } + Ok(ResolvedGenericItem::GenericImplAlias(impl_alias_id)) => { + uninferred_impls.push(UninferredImpl::ImplAlias(impl_alias_id)); + } + _ => {} } } let mut res = Vec::new(); @@ -917,8 +923,7 @@ pub fn find_candidates_at_context( } res.insert(UninferredImpl::GenericParam(*generic_param_id)); } - let core_module = core_module(db); - for module_id in chain!(lookup_context.modules.iter().map(|x| &x.0), [&core_module]) { + for module_id in chain!(lookup_context.modules.iter().map(|x| &x.0)) { let Ok(imps) = db.module_impl_ids_for_trait_filter(*module_id, filter.clone()) else { continue; }; @@ -932,12 +937,12 @@ pub fn find_candidates_at_context( /// Checks if an impl of a trait function with a given self_ty exists. /// This function does not change the state of the inference context. pub fn can_infer_impl_by_self( - ctx: &mut ComputationContext<'_>, + ctx: &ComputationContext<'_>, trait_function_id: TraitFunctionId, self_ty: TypeId, stable_ptr: SyntaxStablePtrId, ) -> bool { - let mut temp_inference_data = ctx.resolver.inference().temporary_clone(); + let mut temp_inference_data = ctx.resolver.data.inference_data.temporary_clone(); let mut temp_inference = temp_inference_data.inference(ctx.db); let lookup_context = ctx.resolver.impl_lookup_context(); let Some((concrete_trait_id, _)) = temp_inference.infer_concrete_trait_by_self( @@ -1020,7 +1025,7 @@ pub fn filter_candidate_traits( candidate_traits: &[TraitId], function_name: SmolStr, stable_ptr: SyntaxStablePtrId, -) -> Maybe> { +) -> Vec { let mut candidates = Vec::new(); for trait_id in candidate_traits.iter().copied() { let Ok(trait_functions) = ctx.db.trait_functions(trait_id) else { @@ -1034,7 +1039,7 @@ pub fn filter_candidate_traits( } } } - Ok(candidates) + candidates } // === Impl Function Declaration === diff --git a/crates/cairo-lang-semantic/src/items/impl_alias.rs b/crates/cairo-lang-semantic/src/items/impl_alias.rs index 8cd62a9dc4b..56fae118d9b 100644 --- a/crates/cairo-lang-semantic/src/items/impl_alias.rs +++ b/crates/cairo-lang-semantic/src/items/impl_alias.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use cairo_lang_defs::ids::{ImplAliasId, ImplDefId, LanguageElementId, LookupItemId, ModuleItemId}; -use cairo_lang_diagnostics::{Diagnostics, Maybe, ToMaybe}; +use cairo_lang_diagnostics::{skip_diagnostic, Diagnostics, Maybe, ToMaybe}; use cairo_lang_proc_macros::DebugWithDb; use cairo_lang_syntax::attribute::structured::{Attribute, AttributeListStructurize}; use cairo_lang_syntax::node::TypedSyntaxNode; @@ -203,9 +203,26 @@ pub fn impl_alias_impl_def(db: &dyn SemanticGroup, impl_alias_id: ImplAliasId) - let impl_path_syntax = impl_alias_ast.impl_path(syntax_db); - resolver - .resolve_generic_path_with_args(&mut diagnostics, &impl_path_syntax, NotFoundItemType::Impl) - .ok() - .and_then(|generic_item| try_extract_matches!(generic_item, ResolvedGenericItem::Impl)) - .ok_or_else(|| diagnostics.report(&impl_path_syntax, NotAnImpl)) + match resolver.resolve_generic_path_with_args( + &mut diagnostics, + &impl_path_syntax, + NotFoundItemType::Impl, + ) { + Ok(ResolvedGenericItem::Impl(imp)) => Ok(imp), + Ok(ResolvedGenericItem::GenericImplAlias(impl_alias)) => db.impl_alias_impl_def(impl_alias), + // Skipping diagnostics since we will get these through when resolving in the + // `priv_impl_alias_semantic_data` query. + _ => Err(skip_diagnostic()), + } +} + +/// Cycle handling for [crate::db::SemanticGroup::impl_alias_impl_def]. +pub fn impl_alias_impl_def_cycle( + _db: &dyn SemanticGroup, + _cycle: &[String], + _impl_alias_id: &ImplAliasId, +) -> Maybe { + // Skipping diagnostics since we will get these through when resolving in the + // `priv_impl_alias_semantic_data` query. + Err(skip_diagnostic()) } diff --git a/tests/bug_samples/indirect_impl_alias.cairo b/tests/bug_samples/indirect_impl_alias.cairo new file mode 100644 index 00000000000..347e8c8316c --- /dev/null +++ b/tests/bug_samples/indirect_impl_alias.cairo @@ -0,0 +1,26 @@ +trait Trait1 { + fn func1(value: T); +} + +trait Trait2 { + fn func2(value: T); +} + +mod impls { + impl Impl1> of super::Trait1 { + fn func1(value: T) {} + } + impl ImplAlias1 = Impl1; + impl Impl2> of super::Trait2 { + fn func2(value: T) {} + } + impl ImplAlias2 = Impl2; +} + +use impls::ImplAlias1; +impl Impl2 = impls::ImplAlias2; + +fn foo() { + Trait1::func1(0_felt252); + Trait2::func2(0_felt252); +} diff --git a/tests/bug_samples/lib.cairo b/tests/bug_samples/lib.cairo index 8b2ff9f727f..b94eb2bbe5b 100644 --- a/tests/bug_samples/lib.cairo +++ b/tests/bug_samples/lib.cairo @@ -1,4 +1,5 @@ mod ecdsa_completeness; +mod indirect_impl_alias; mod issue2114; mod issue2147; mod issue2152;