Skip to content

Commit

Permalink
added validations for traitItemInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
dean-starkware committed Feb 9, 2025
1 parent d565dfd commit effa77e
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 49 deletions.
2 changes: 1 addition & 1 deletion corelib/src/starknet/storage/vec.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ impl MutableVecImpl<T> of MutableVecTrait<StoragePath<Mutable<Vec<T>>>> {
fn push<+Drop<Self::ElementType>, +starknet::Store<Self::ElementType>>(
self: StoragePath<Mutable<Vec<T>>>, value: Self::ElementType,
) {
self.append().write(value);
self.allocate().write(value);
}

fn pop<+Drop<Self::ElementType>, +starknet::Store<Self::ElementType>>(
Expand Down
66 changes: 66 additions & 0 deletions crates/cairo-lang-semantic/src/diagnostic_test_data/tests
Original file line number Diff line number Diff line change
Expand Up @@ -1267,3 +1267,69 @@ error: Global `use` item is not supported in `V2023_01` edition.
--> lib.cairo:4:8
use a::*;
^

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

//! > Test usage of deprecated trait function (via function path).

//! > test_runner_name
test_expr_diagnostics(expect_diagnostics: warnings_only)

//! > expr_code
{
let x = Struct {};
MyTrait::deprecated_method(@x);
}

//! > module_code
pub struct Struct {}

pub trait MyTrait {
#[deprecated(feature: "deprecated", note: "This method is deprecated", since: "1.0.0")]
fn deprecated_method(self: @Struct);
}

impl MyTraitImpl of MyTrait {
fn deprecated_method(self: @Struct) {}
}

//! > function_body

//! > expected_diagnostics
warning: Usage of deprecated feature `"deprecated"` with no `#[feature("deprecated")]` attribute. Note: "This method is deprecated"
--> lib.cairo:14:12
MyTrait::deprecated_method(@x);
^^^^^^^^^^^^^^^^^

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

//! > Test usage of deprecated trait function (via method).

//! > test_runner_name
test_expr_diagnostics(expect_diagnostics: warnings_only)

//! > expr_code
{
let x = Struct {};
x.deprecated_method();
}

//! > module_code
pub struct Struct {}

pub trait MyTrait {
#[deprecated(feature: "deprecated", note: "This method is deprecated", since: "1.0.0")]
fn deprecated_method(self: @Struct);
}

impl MyTraitImpl of MyTrait {
fn deprecated_method(self: @Struct) {}
}

//! > function_body

//! > expected_diagnostics
warning: Usage of deprecated feature `"deprecated"` with no `#[feature("deprecated")]` attribute. Note: "This method is deprecated"
--> lib.cairo:14:5
x.deprecated_method();
^^^^^^^^^^^^^^^^^
13 changes: 11 additions & 2 deletions crates/cairo-lang-semantic/src/expr/compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2869,7 +2869,7 @@ fn method_call_expr(
compute_method_function_call_data(
ctx,
candidate_traits.keys().copied().collect_vec().as_slice(),
func_name,
func_name.clone(),
lexpr,
path.stable_ptr().untyped(),
generic_args_syntax,
Expand All @@ -2892,8 +2892,17 @@ fn method_call_expr(
Some(AmbiguousTrait { trait_function_id0, trait_function_id1 })
},
)?;
ctx.resolver.data.used_items.insert(candidate_traits[&actual_trait_id]);

if let Ok(trait_definition_data) = ctx.db.priv_trait_definition_data(actual_trait_id) {
if let Some(trait_item_info) = trait_definition_data.get_trait_item_info(&func_name) {
ctx.resolver.validate_feature_constraints(
ctx.diagnostics,
&segment.identifier_ast(db.upcast()),
&trait_item_info,
);
}
}
ctx.resolver.data.used_items.insert(candidate_traits[&actual_trait_id]);
ctx.resolver.data.resolved_items.mark_concrete(
ctx.db,
&segment,
Expand Down
6 changes: 6 additions & 0 deletions crates/cairo-lang-semantic/src/items/feature_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ impl FeatureKind {
}
}

/// A trait for retrieving the `FeatureKind` of an item.
pub trait HasFeatureKind {
/// Returns the `FeatureKind` associated with the implementing struct.
fn feature_kind(&self) -> &FeatureKind;
}

/// Diagnostics for feature markers.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum FeatureMarkerDiagnostic {
Expand Down
7 changes: 7 additions & 0 deletions crates/cairo-lang-semantic/src/items/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use super::visibility::{Visibility, peek_visible_in};
use crate::SemanticDiagnostic;
use crate::db::{SemanticGroup, get_resolver_data_options};
use crate::diagnostic::{SemanticDiagnosticKind, SemanticDiagnosticsBuilder};
use crate::items::feature_kind::HasFeatureKind;
use crate::resolve::ResolvedGenericItem;

/// Information per item in a module.
Expand Down Expand Up @@ -284,3 +285,9 @@ fn specific_module_usable_trait_ids(
}
Ok(module_traits)
}

impl HasFeatureKind for ModuleItemInfo {
fn feature_kind(&self) -> &FeatureKind {
&self.feature_kind
}
}
70 changes: 60 additions & 10 deletions crates/cairo-lang-semantic/src/items/trt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use cairo_lang_utils::{Intern, LookupIntern, define_short_id};
use smol_str::SmolStr;

use super::TraitOrImplContext;
use super::feature_kind::FeatureKind;
use super::function_with_body::{FunctionBodyData, get_implicit_precedence, get_inline_config};
use super::functions::{
FunctionDeclarationData, GenericFunctionId, ImplGenericFunctionId, ImplicitPrecedence,
Expand All @@ -36,6 +37,7 @@ use crate::diagnostic::{NotFoundItemType, SemanticDiagnostics, SemanticDiagnosti
use crate::expr::compute::{ComputationContext, ContextFunction, Environment, compute_root_expr};
use crate::expr::inference::InferenceId;
use crate::expr::inference::canonic::ResultNoErrEx;
use crate::items::feature_kind::HasFeatureKind;
use crate::resolve::{ResolvedConcreteItem, Resolver, ResolverData};
use crate::substitution::{GenericSubstitution, SemanticRewriter, SubstitutionRewriter};
use crate::types::resolve_type;
Expand Down Expand Up @@ -477,7 +479,29 @@ pub struct TraitDefinitionData {
item_impl_asts: OrderedHashMap<TraitImplId, ast::TraitItemImpl>,

/// Mapping of item names to their IDs. All the IDs should appear in one of the AST maps above.
item_id_by_name: Arc<OrderedHashMap<SmolStr, TraitItemId>>,
item_id_by_name: Arc<OrderedHashMap<SmolStr, TraitItemInfo>>,
}

impl TraitDefinitionData {
/// Retrieves trait item information by its name.
pub fn get_trait_item_info(&self, item_name: &SmolStr) -> Option<TraitItemInfo> {
self.item_id_by_name.get(item_name).cloned()
}
}
/// Stores metadata for a trait item, including its ID and feature kind.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TraitItemInfo {
/// The unique identifier of the trait item.
pub id: TraitItemId,
/// The feature kind associated with this trait item.
pub feature_kind: FeatureKind,
}

impl HasFeatureKind for TraitItemInfo {
/// Returns the feature kind of this trait item.
fn feature_kind(&self) -> &FeatureKind {
&self.feature_kind
}
}

// --- Selectors ---
Expand Down Expand Up @@ -520,7 +544,7 @@ pub fn trait_required_item_names(
) -> Maybe<OrderedHashSet<SmolStr>> {
let mut required_items = OrderedHashSet::<_>::default();
for (item_name, item_id) in db.priv_trait_definition_data(trait_id)?.item_id_by_name.iter() {
if match item_id {
if match item_id.id {
TraitItemId::Function(id) => {
let body = id.stable_ptr(db.upcast()).lookup(db.upcast()).body(db.upcast());
matches!(body, ast::MaybeTraitFunctionBody::None(_))
Expand All @@ -540,7 +564,7 @@ pub fn trait_item_by_name(
trait_id: TraitId,
name: SmolStr,
) -> Maybe<Option<TraitItemId>> {
Ok(db.priv_trait_definition_data(trait_id)?.item_id_by_name.get(&name).cloned())
Ok(db.priv_trait_definition_data(trait_id)?.item_id_by_name.get(&name).map(|info| info.id))
}

/// Query implementation of [SemanticGroup::trait_all_used_items].
Expand All @@ -551,7 +575,7 @@ pub fn trait_all_used_items(
let mut all_used_items = db.trait_resolver_data(trait_id)?.used_items.clone();
let data = db.priv_trait_definition_data(trait_id)?;
for item in data.item_id_by_name.values() {
for resolver_data in get_resolver_data_options(LookupItemId::TraitItem(*item), db) {
for resolver_data in get_resolver_data_options(LookupItemId::TraitItem(item.id), db) {
all_used_items.extend(resolver_data.used_items.iter().cloned());
}
}
Expand Down Expand Up @@ -679,7 +703,7 @@ pub fn priv_trait_definition_data(
let mut item_type_asts = OrderedHashMap::default();
let mut item_constant_asts = OrderedHashMap::default();
let mut item_impl_asts = OrderedHashMap::default();
let mut item_id_by_name = OrderedHashMap::default();
let mut item_id_by_name: OrderedHashMap<SmolStr, TraitItemInfo> = OrderedHashMap::default();

if let ast::MaybeTraitBody::Some(body) = trait_ast.body(syntax_db) {
for item in body.items(syntax_db).elements(syntax_db) {
Expand All @@ -689,8 +713,14 @@ pub fn priv_trait_definition_data(
TraitFunctionLongId(module_file_id, func.stable_ptr()).intern(db);
let name_node = func.declaration(syntax_db).name(syntax_db);
let name = name_node.text(syntax_db);
let attributes = func.attributes(syntax_db);
let feature_kind =
FeatureKind::from_ast(db.upcast(), &mut diagnostics, &attributes);
if item_id_by_name
.insert(name.clone(), TraitItemId::Function(trait_func_id))
.insert(name.clone(), TraitItemInfo {
id: TraitItemId::Function(trait_func_id),
feature_kind,
})
.is_some()
{
diagnostics.report(
Expand All @@ -704,8 +734,14 @@ pub fn priv_trait_definition_data(
let trait_type_id = TraitTypeLongId(module_file_id, ty.stable_ptr()).intern(db);
let name_node = ty.name(syntax_db);
let name = name_node.text(syntax_db);
let attributes = ty.attributes(syntax_db);
let feature_kind =
FeatureKind::from_ast(db.upcast(), &mut diagnostics, &attributes);
if item_id_by_name
.insert(name.clone(), TraitItemId::Type(trait_type_id))
.insert(name.clone(), TraitItemInfo {
id: TraitItemId::Type(trait_type_id),
feature_kind,
})
.is_some()
{
diagnostics.report(
Expand All @@ -721,8 +757,14 @@ pub fn priv_trait_definition_data(

let name_node = constant.name(syntax_db);
let name = name_node.text(syntax_db);
let attributes = constant.attributes(syntax_db);
let feature_kind =
FeatureKind::from_ast(db.upcast(), &mut diagnostics, &attributes);
if item_id_by_name
.insert(name.clone(), TraitItemId::Constant(trait_constant))
.insert(name.clone(), TraitItemInfo {
id: TraitItemId::Constant(trait_constant),
feature_kind,
})
.is_some()
{
diagnostics.report(
Expand All @@ -737,7 +779,15 @@ pub fn priv_trait_definition_data(

let name_node = imp.name(syntax_db);
let name = name_node.text(syntax_db);
if item_id_by_name.insert(name.clone(), TraitItemId::Impl(trait_impl)).is_some()
let attributes = imp.attributes(syntax_db);
let feature_kind =
FeatureKind::from_ast(db.upcast(), &mut diagnostics, &attributes);
if item_id_by_name
.insert(name.clone(), TraitItemInfo {
id: TraitItemId::Impl(trait_impl),
feature_kind,
})
.is_some()
{
diagnostics.report(
&name_node,
Expand All @@ -757,7 +807,7 @@ pub fn priv_trait_definition_data(
item_type_asts,
item_constant_asts,
item_impl_asts,
item_id_by_name: item_id_by_name.into(),
item_id_by_name: Arc::new(item_id_by_name),
})
}

Expand Down
Loading

0 comments on commit effa77e

Please sign in to comment.