Skip to content

Commit

Permalink
added cycle detection for generic params (#6094)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomerStarkware authored Jul 30, 2024
1 parent b88688c commit 190dd83
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 29 deletions.
2 changes: 2 additions & 0 deletions crates/cairo-lang-semantic/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,11 @@ pub trait SemanticGroup:
) -> Diagnostics<SemanticDiagnostic>;
/// Returns the generic parameters of a trait.
#[salsa::invoke(items::trt::trait_generic_params)]
#[salsa::cycle(items::trt::trait_generic_params_cycle)]
fn trait_generic_params(&self, trait_id: TraitId) -> Maybe<Vec<GenericParam>>;
/// Returns the generic parameters data of a trait.
#[salsa::invoke(items::trt::trait_generic_params_data)]
#[salsa::cycle(items::trt::trait_generic_params_data_cycle)]
fn trait_generic_params_data(&self, trait_id: TraitId) -> Maybe<GenericParamsData>;
/// Returns the attributes of a trait.
#[salsa::invoke(items::trt::trait_attributes)]
Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-semantic/src/items/enm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ pub fn enum_generic_params_data(
&mut resolver,
module_file_id,
&enum_ast.generic_params(db.upcast()),
)?;
);
let inference = &mut resolver.inference();
inference.finalize(&mut diagnostics, enum_ast.stable_ptr().untyped());

Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-semantic/src/items/extern_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub fn extern_function_declaration_generic_params_data(
&mut resolver,
module_file_id,
&declaration.generic_params(syntax_db),
)?;
);

let inference = &mut resolver.inference();
inference.finalize(&mut diagnostics, extern_function_syntax.stable_ptr().untyped());
Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-semantic/src/items/extern_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ pub fn extern_type_declaration_generic_params_data(
&mut resolver,
module_file_id,
&extern_type_syntax.generic_params(db.upcast()),
)?;
);
if let Some(param) = generic_params.iter().find(|param| param.kind() == GenericKind::Impl) {
diagnostics.report(
param.stable_ptr(db.upcast()).untyped(),
Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-semantic/src/items/free_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub fn free_function_generic_params_data(
&mut resolver,
module_file_id,
&declaration.generic_params(syntax_db),
)?;
);

let inference = &mut resolver.inference();
inference.finalize(&mut diagnostics, free_function_syntax.stable_ptr().untyped());
Expand Down
38 changes: 22 additions & 16 deletions crates/cairo-lang-semantic/src/items/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ pub struct GenericParamImpl {
#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)]
#[debug_db(dyn SemanticGroup + 'static)]
pub struct GenericParamData {
pub generic_param: GenericParam,
pub generic_param: Maybe<GenericParam>,
pub diagnostics: Diagnostics<SemanticDiagnostic>,
pub resolver_data: Arc<ResolverData>,
}
Expand All @@ -216,7 +216,7 @@ pub fn generic_param_semantic(
db: &dyn SemanticGroup,
generic_param_id: GenericParamId,
) -> Maybe<GenericParam> {
Ok(db.priv_generic_param_data(generic_param_id)?.generic_param)
db.priv_generic_param_data(generic_param_id)?.generic_param
}

/// Query implementation of [crate::db::SemanticGroup::generic_param_diagnostics].
Expand Down Expand Up @@ -329,7 +329,7 @@ pub fn priv_generic_param_data(
let param_semantic = inference.rewrite(param_semantic).no_err();
let resolver_data = Arc::new(resolver.data);
Ok(GenericParamData {
generic_param: param_semantic,
generic_param: Ok(param_semantic),
diagnostics: diagnostics.build(),
resolver_data,
})
Expand All @@ -342,10 +342,17 @@ pub fn priv_generic_param_data_cycle(
generic_param_id: &GenericParamId,
) -> Maybe<GenericParamData> {
let mut diagnostics = SemanticDiagnostics::default();
Err(diagnostics.report(
generic_param_id.stable_ptr(db.upcast()).untyped(),
SemanticDiagnosticKind::ImplRequirementCycle,
))
Ok(GenericParamData {
generic_param: Err(diagnostics.report(
generic_param_id.stable_ptr(db.upcast()).untyped(),
SemanticDiagnosticKind::ImplRequirementCycle,
)),
diagnostics: diagnostics.build(),
resolver_data: Arc::new(ResolverData::new(
generic_param_id.module_file_id(db.upcast()),
InferenceId::GenericParam(*generic_param_id),
)),
})
}

// --- Helpers ---
Expand All @@ -372,26 +379,25 @@ pub fn semantic_generic_params(
resolver: &mut Resolver<'_>,
module_file_id: ModuleFileId,
generic_params: &ast::OptionWrappedGenericParamList,
) -> Maybe<Vec<GenericParam>> {
) -> Vec<GenericParam> {
let syntax_db = db.upcast();
let res = match generic_params {
syntax::node::ast::OptionWrappedGenericParamList::Empty(_) => Ok(vec![]),
match generic_params {
syntax::node::ast::OptionWrappedGenericParamList::Empty(_) => vec![],
syntax::node::ast::OptionWrappedGenericParamList::WrappedGenericParamList(syntax) => syntax
.generic_params(syntax_db)
.elements(syntax_db)
.iter()
.map(|param_syntax| {
.filter_map(|param_syntax| {
let generic_param_id =
GenericParamLongId(module_file_id, param_syntax.stable_ptr()).intern(db);
let generic_param_data = db.priv_generic_param_data(generic_param_id)?;
let generic_param_data = db.priv_generic_param_data(generic_param_id).ok()?;
let generic_param = generic_param_data.generic_param;
diagnostics.extend(generic_param_data.diagnostics);
resolver.add_generic_param(generic_param_id);
Ok(generic_param)
generic_param.ok()
})
.collect::<Result<Vec<_>, _>>(),
};
res
.collect(),
}
}

/// Returns true if negative impls are enabled in the module.
Expand Down
4 changes: 2 additions & 2 deletions crates/cairo-lang-semantic/src/items/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ pub fn impl_def_generic_params_data(
&mut resolver,
module_file_id,
&impl_ast.generic_params(db.upcast()),
)?;
);
let inference = &mut resolver.inference();
inference.finalize(&mut diagnostics, impl_ast.stable_ptr().untyped());

Expand Down Expand Up @@ -2613,7 +2613,7 @@ pub fn priv_impl_function_generic_params_data(
&mut resolver,
module_file_id,
&declaration.generic_params(syntax_db),
)?;
);
let inference = &mut resolver.inference();
inference.finalize(&mut diagnostics, function_syntax.stable_ptr().untyped());

Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-semantic/src/items/impl_alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ pub fn impl_alias_generic_params_data_helper(
&mut resolver,
module_file_id,
&impl_alias_ast.generic_params(db.upcast()),
)?;
);

let inference = &mut resolver.inference();
inference.finalize(&mut diagnostics, impl_alias_ast.stable_ptr().untyped());
Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-semantic/src/items/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ pub fn struct_generic_params_data(
&mut resolver,
module_file_id,
&struct_ast.generic_params(db.upcast()),
)?;
);
let inference = &mut resolver.inference();
inference.finalize(&mut diagnostics, struct_ast.stable_ptr().untyped());

Expand Down
55 changes: 55 additions & 0 deletions crates/cairo-lang-semantic/src/items/tests/trait
Original file line number Diff line number Diff line change
Expand Up @@ -1247,3 +1247,58 @@ fn bar<impl I: Tr>(x: A<I>) -> A<I> {
}

//! > expected_diagnostics

//! > ==========================================================================

//! > trait cycle of generics.

//! > test_runner_name
test_function_diagnostics(expect_diagnostics: *)

//! > function
fn foo() -> felt252 {
2
}

//! > function_name
foo

//! > module_code
pub trait Tr<+Tr> {}

//! > expected_diagnostics
error: Cycle detected while resolving generic param. Try specifying the generic impl parameter explicitly to break the cycle.
--> lib.cairo:1:14
pub trait Tr<+Tr> {}
^*^

//! > ==========================================================================

//! > cycle with anonymous impl with impl alias instead of trait.

//! > test_runner_name
test_function_diagnostics(expect_diagnostics: *)

//! > function
fn foo() -> felt252 {
2
}

//! > function_name
foo

//! > module_code
trait Tr {}
impl I0<T, +Ifelt252> of Tr {}
impl Ifelt = I0<Ifelt>;

//! > expected_diagnostics
error: Trait not found.
--> lib.cairo:2:13
impl I0<T, +Ifelt252> of Tr {}
^******^

error: Cycle detected while resolving 'impls alias' items.
--> lib.cairo:3:6
impl Ifelt = I0<Ifelt>;
^***^
25 changes: 21 additions & 4 deletions crates/cairo-lang-semantic/src/items/trt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,15 @@ pub fn trait_semantic_declaration_diagnostics(
pub fn trait_generic_params(db: &dyn SemanticGroup, trait_id: TraitId) -> Maybe<Vec<GenericParam>> {
Ok(db.trait_generic_params_data(trait_id)?.generic_params)
}
/// Cycle handling for [crate::db::SemanticGroup::trait_generic_params].
pub fn trait_generic_params_cycle(
db: &dyn SemanticGroup,
_cycle: &[String],
trait_id: &TraitId,
) -> Maybe<Vec<GenericParam>> {
// Forwarding cycle handling to `priv_generic_param_data` handler.
trait_generic_params(db, *trait_id)
}

/// Query implementation of [crate::db::SemanticGroup::trait_generic_params_data].
pub fn trait_generic_params_data(
Expand All @@ -365,7 +374,7 @@ pub fn trait_generic_params_data(
&mut resolver,
module_file_id,
&trait_ast.generic_params(syntax_db),
)?;
);

let inference = &mut resolver.inference();
inference.finalize(&mut diagnostics, trait_ast.stable_ptr().untyped());
Expand All @@ -374,7 +383,15 @@ pub fn trait_generic_params_data(
let resolver_data = Arc::new(resolver.data);
Ok(GenericParamsData { diagnostics: diagnostics.build(), generic_params, resolver_data })
}

/// Cycle handling for [crate::db::SemanticGroup::trait_generic_params_data].
pub fn trait_generic_params_data_cycle(
db: &dyn SemanticGroup,
_cycle: &[String],
trait_id: &TraitId,
) -> Maybe<GenericParamsData> {
// Forwarding cycle handling to `priv_generic_param_data` handler.
trait_generic_params_data(db, *trait_id)
}
/// Query implementation of [crate::db::SemanticGroup::trait_attributes].
pub fn trait_attributes(db: &dyn SemanticGroup, trait_id: TraitId) -> Maybe<Vec<Attribute>> {
Ok(db.priv_trait_declaration_data(trait_id)?.attributes)
Expand Down Expand Up @@ -788,7 +805,7 @@ pub fn priv_trait_type_generic_params_data(
&mut resolver,
module_file_id,
&generic_params_node,
)?;
);
let type_generic_params = resolver.inference().rewrite(type_generic_params).no_err();

// TODO(yuval): support generics in impls (including validation), then remove this.
Expand Down Expand Up @@ -1085,7 +1102,7 @@ pub fn priv_trait_function_generic_params_data(
&mut resolver,
module_file_id,
&declaration.generic_params(syntax_db),
)?;
);
let function_generic_params = resolver.inference().rewrite(function_generic_params).no_err();
let resolver_data = Arc::new(resolver.data);
Ok(GenericParamsData {
Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-semantic/src/items/type_aliases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn type_alias_generic_params_data_helper(
&mut resolver,
module_file_id,
&type_alias_ast.generic_params(db.upcast()),
)?;
);

let inference = &mut resolver.inference();
inference.finalize(&mut diagnostics, type_alias_ast.stable_ptr().untyped());
Expand Down

0 comments on commit 190dd83

Please sign in to comment.