Skip to content

Commit

Permalink
Added indirect impl support for inference. (#4420)
Browse files Browse the repository at this point in the history
  • Loading branch information
orizi authored Nov 19, 2023
1 parent c8444c2 commit 8af8df3
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 38 deletions.
1 change: 1 addition & 0 deletions crates/cairo-lang-semantic/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ImplDefId>;
/// Private query to compute data about a type alias.
#[salsa::invoke(items::impl_alias::priv_impl_alias_semantic_data)]
Expand Down
24 changes: 1 addition & 23 deletions crates/cairo-lang-semantic/src/expr/compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() },
Expand Down Expand Up @@ -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
Expand Down
23 changes: 14 additions & 9 deletions crates/cairo-lang-semantic/src/items/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
};
Expand All @@ -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(
Expand Down Expand Up @@ -1020,7 +1025,7 @@ pub fn filter_candidate_traits(
candidate_traits: &[TraitId],
function_name: SmolStr,
stable_ptr: SyntaxStablePtrId,
) -> Maybe<Vec<TraitFunctionId>> {
) -> Vec<TraitFunctionId> {
let mut candidates = Vec::new();
for trait_id in candidate_traits.iter().copied() {
let Ok(trait_functions) = ctx.db.trait_functions(trait_id) else {
Expand All @@ -1034,7 +1039,7 @@ pub fn filter_candidate_traits(
}
}
}
Ok(candidates)
candidates
}

// === Impl Function Declaration ===
Expand Down
29 changes: 23 additions & 6 deletions crates/cairo-lang-semantic/src/items/impl_alias.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<ImplDefId> {
// Skipping diagnostics since we will get these through when resolving in the
// `priv_impl_alias_semantic_data` query.
Err(skip_diagnostic())
}
26 changes: 26 additions & 0 deletions tests/bug_samples/indirect_impl_alias.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
trait Trait1<T> {
fn func1(value: T);
}

trait Trait2<T> {
fn func2(value: T);
}

mod impls {
impl Impl1<T, +Drop<T>> of super::Trait1<T> {
fn func1(value: T) {}
}
impl ImplAlias1 = Impl1<felt252>;
impl Impl2<T, +Drop<T>> of super::Trait2<T> {
fn func2(value: T) {}
}
impl ImplAlias2 = Impl2<felt252>;
}

use impls::ImplAlias1;
impl Impl2 = impls::ImplAlias2;

fn foo() {
Trait1::func1(0_felt252);
Trait2::func2(0_felt252);
}
1 change: 1 addition & 0 deletions tests/bug_samples/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod ecdsa_completeness;
mod indirect_impl_alias;
mod issue2114;
mod issue2147;
mod issue2152;
Expand Down

0 comments on commit 8af8df3

Please sign in to comment.