Skip to content
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

added cycle detection for generic params #6094

Merged
merged 1 commit into from
Jul 30, 2024
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
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