Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8784cb6
Write some new bugs
jfecher Jun 25, 2025
8bce44d
Debugging
jfecher Jun 26, 2025
d9d4ea3
Re-add TraitItemId
jfecher Jun 27, 2025
99cf1ae
Minor changes
jfecher Jun 27, 2025
cabfdf3
Add debug lines
jfecher Jul 1, 2025
f17e241
Fix errors in stdlib
jfecher Jul 1, 2025
ab27430
Only 'trait_bounds_which_are_dependent...' is failing now, the bounds…
jfecher Jul 1, 2025
37cb7e9
It works
jfecher Jul 2, 2025
78f74ab
Ignore new test in nargo expand
jfecher Jul 2, 2025
22f8da3
Format
jfecher Jul 2, 2025
1900d26
Merge branch 'master' into jf/assoc-consts
jfecher Jul 2, 2025
87fe1a8
Apply suggestions from code review
jfecher Jul 2, 2025
5d70a6c
Update test_programs/compile_success_empty/comptime_function_definiti…
jfecher Jul 2, 2025
a530cd0
Update expect message
asterite Jul 3, 2025
b32fa9b
Update `populate_dummy_operator_traits`
asterite Jul 3, 2025
06cf01e
Follow bindings in error field
asterite Jul 3, 2025
a32c8d3
Use correct `trait_it` when looking up trait method
asterite Jul 3, 2025
860816b
Test associated constant of generic with constraint
asterite Jul 3, 2025
af5ffa5
Reduce number of lines
asterite Jul 3, 2025
3a432a0
More lines reduction
asterite Jul 3, 2025
934acb5
Remove extra line
asterite Jul 3, 2025
a560ed7
Make sure it works in comptime
asterite Jul 3, 2025
d16d5e4
Add a few more comments
asterite Jul 3, 2025
12c6abe
Bring back check
asterite Jul 3, 2025
765b007
resolve_trait_method_expr -> resolve_trait_item_expr
asterite Jul 3, 2025
889fee8
No need for method to be pub
asterite Jul 3, 2025
5665fc2
A couple more pub -> pub(crate)
asterite Jul 3, 2025
41d25ee
Merge branch 'master' into jf/assoc-consts
asterite Jul 3, 2025
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
60 changes: 31 additions & 29 deletions compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ use crate::{
HirConstrainExpression, HirConstructorExpression, HirExpression, HirIdent,
HirIfExpression, HirIndexExpression, HirInfixExpression, HirLambda, HirLiteral,
HirMatch, HirMemberAccess, HirMethodCallExpression, HirPrefixExpression, ImplKind,
TraitMethod,
TraitItem,
},
stmt::{HirLetStatement, HirPattern, HirStatement},
traits::{ResolvedTraitBound, TraitConstraint},
},
node_interner::{
DefinitionId, DefinitionKind, ExprId, FuncId, InternedStatementKind, StmtId, TraitMethodId,
DefinitionId, DefinitionKind, ExprId, FuncId, InternedStatementKind, StmtId, TraitItemId,
},
shared::Signedness,
token::{FmtStrFragment, IntegerTypeSuffix, Tokens},
Expand Down Expand Up @@ -405,7 +405,7 @@ impl Elaborator<'_> {
let rhs_location = prefix.rhs.location;

let (rhs, rhs_type) = self.elaborate_expression(prefix.rhs);
let trait_id = self.interner.get_prefix_operator_trait_method(&prefix.operator);
let trait_method_id = self.interner.get_prefix_operator_trait_method(&prefix.operator);

let operator = prefix.operator;

Expand All @@ -417,14 +417,18 @@ impl Elaborator<'_> {
}
}

let expr =
HirExpression::Prefix(HirPrefixExpression { operator, rhs, trait_method_id: trait_id });
let expr = HirExpression::Prefix(HirPrefixExpression { operator, rhs, trait_method_id });
let expr_id = self.interner.push_expr(expr);
self.interner.push_expr_location(expr_id, location);

let result = self.prefix_operand_type_rules(&operator, &rhs_type, location);
let typ =
self.handle_operand_type_rules_result(result, &rhs_type, trait_id, expr_id, location);
let typ = self.handle_operand_type_rules_result(
result,
&rhs_type,
trait_method_id,
expr_id,
location,
);

self.interner.push_expr_type(expr_id, typ.clone());
(expr_id, typ)
Expand Down Expand Up @@ -1078,32 +1082,31 @@ impl Elaborator<'_> {
&mut self,
result: Result<(Type, bool), TypeCheckError>,
operand_type: &Type,
trait_id: Option<TraitMethodId>,
trait_method_id: Option<TraitItemId>,
expr_id: ExprId,
location: Location,
) -> Type {
match result {
Ok((typ, use_impl)) => {
if use_impl {
let trait_id =
trait_id.expect("ice: expected some trait_id when use_impl is true");
let trait_method_id = trait_method_id
.expect("ice: expected some trait_method_id when use_impl is true");

// Delay checking the trait constraint until the end of the function.
// Checking it now could bind an unbound type variable to any type
// that implements the trait.
let constraint = TraitConstraint {
typ: operand_type.clone(),
trait_bound: ResolvedTraitBound {
trait_id: trait_id.trait_id,
trait_generics: TraitGenerics::default(),
location,
},
};
self.push_trait_constraint(
constraint, expr_id,
true, // this constraint should lead to choosing a trait impl
let trait_id = trait_method_id.trait_id;
let trait_generics = TraitGenerics::default();
let trait_bound = ResolvedTraitBound { trait_id, trait_generics, location };
let constraint = TraitConstraint { typ: operand_type.clone(), trait_bound };
let select_impl = true; // this constraint should lead to choosing a trait impl
self.push_trait_constraint(constraint, expr_id, select_impl);
self.type_check_operator_method(
expr_id,
trait_method_id,
operand_type,
location,
);
self.type_check_operator_method(expr_id, trait_id, operand_type, location);
}
typ
}
Expand Down Expand Up @@ -1471,7 +1474,9 @@ impl Elaborator<'_> {
let constraint = TraitConstraint { typ, trait_bound };

let the_trait = self.interner.get_trait(constraint.trait_bound.trait_id);
let Some(method) = the_trait.find_method(path.impl_item.as_str()) else {
let Some(definition) =
the_trait.find_method_or_constant(path.impl_item.as_str(), self.interner)
else {
let trait_name = the_trait.name.to_string();
let method_name = path.impl_item.to_string();
let location = path.impl_item.location();
Expand All @@ -1480,15 +1485,12 @@ impl Elaborator<'_> {
return (error, Type::Error);
};

let trait_method =
TraitMethod { method_id: method, constraint: constraint.clone(), assumed: true };

let definition_id = self.interner.trait_method_id(trait_method.method_id);
let trait_item = TraitItem { definition, constraint: constraint.clone(), assumed: true };

let ident = HirIdent {
location: path.impl_item.location(),
id: definition_id,
impl_kind: ImplKind::TraitMethod(trait_method),
id: definition,
impl_kind: ImplKind::TraitItem(trait_item),
};

let id = self.interner.push_expr(HirExpression::Ident(ident.clone(), None));
Expand Down
18 changes: 9 additions & 9 deletions compiler/noirc_frontend/src/elaborator/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
type_check::{Source, TypeCheckError},
},
hir_def::{
expr::{HirExpression, HirIdent, HirLiteral, HirMethodReference, ImplKind, TraitMethod},
expr::{HirExpression, HirIdent, HirLiteral, HirMethodReference, ImplKind, TraitItem},
stmt::HirPattern,
},
node_interner::{
Expand Down Expand Up @@ -904,11 +904,11 @@ impl Elaborator<'_> {
trait_path_resolution.item,
),

TraitPathResolutionMethod::TraitMethod(trait_method) => (
TraitPathResolutionMethod::TraitItem(item) => (
HirIdent {
location: path.location,
id: self.interner.trait_method_id(trait_method.method_id),
impl_kind: ImplKind::TraitMethod(trait_method),
id: item.definition,
impl_kind: ImplKind::TraitItem(item),
},
trait_path_resolution.item,
),
Expand Down Expand Up @@ -1006,7 +1006,7 @@ impl Elaborator<'_> {
// We need to do this first since otherwise instantiating the type below
// will replace each trait generic with a fresh type variable, rather than
// the type used in the trait constraint (if it exists). See #4088.
if let ImplKind::TraitMethod(method) = &ident.impl_kind {
if let ImplKind::TraitItem(method) = &ident.impl_kind {
self.bind_generics_from_trait_constraint(
&method.constraint,
method.assumed,
Expand Down Expand Up @@ -1053,7 +1053,7 @@ impl Elaborator<'_> {
}
}

if let ImplKind::TraitMethod(mut method) = ident.impl_kind {
if let ImplKind::TraitItem(mut method) = ident.impl_kind {
method.constraint.apply_bindings(&bindings);
if method.assumed {
let trait_generics = method.constraint.trait_bound.trait_generics.clone();
Expand Down Expand Up @@ -1196,11 +1196,11 @@ impl Elaborator<'_> {

let impl_kind = match method {
HirMethodReference::FuncId(_) => ImplKind::NotATraitMethod,
HirMethodReference::TraitMethodId(method_id, generics, _) => {
HirMethodReference::TraitItemId(definition, trait_id, generics, _) => {
let mut constraint =
self.interner.get_trait(method_id.trait_id).as_constraint(ident_location);
self.interner.get_trait(trait_id).as_constraint(ident_location);
constraint.trait_bound.trait_generics = generics;
ImplKind::TraitMethod(TraitMethod { method_id, constraint, assumed: false })
ImplKind::TraitItem(TraitItem { definition, constraint, assumed: false })
}
};

Expand Down
69 changes: 36 additions & 33 deletions compiler/noirc_frontend/src/elaborator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ use crate::{
hir_def::{
expr::{
HirBinaryOp, HirCallExpression, HirExpression, HirLiteral, HirMemberAccess,
HirMethodReference, HirPrefixExpression, TraitMethod,
HirMethodReference, HirPrefixExpression, TraitItem,
},
function::FuncMeta,
stmt::HirStatement,
traits::{NamedType, ResolvedTraitBound, Trait, TraitConstraint},
},
node_interner::{
DependencyId, ExprId, FuncId, GlobalValue, ImplSearchErrorKind, TraitId, TraitImplKind,
TraitMethodId,
TraitItemId,
},
shared::Signedness,
token::SecondaryAttributeKind,
Expand All @@ -55,7 +55,7 @@ pub(super) struct TraitPathResolution {

pub(super) enum TraitPathResolutionMethod {
NotATraitMethod(FuncId),
TraitMethod(TraitMethod),
TraitItem(TraitItem),
}

impl Elaborator<'_> {
Expand Down Expand Up @@ -734,10 +734,12 @@ impl Elaborator<'_> {

if name == SELF_TYPE_NAME {
let the_trait = self.interner.get_trait(trait_id);
let method = the_trait.find_method(method.as_str())?;
// Allow referring to trait constants via Self:: as well
let definition =
the_trait.find_method_or_constant(method.as_str(), self.interner)?;
let constraint = the_trait.as_constraint(path.location);
let trait_method = TraitMethod { method_id: method, constraint, assumed: true };
let method = TraitPathResolutionMethod::TraitMethod(trait_method);
let trait_method = TraitItem { definition, constraint, assumed: true };
let method = TraitPathResolutionMethod::TraitItem(trait_method);
return Some(TraitPathResolution { method, item: None, errors: Vec::new() });
}
}
Expand All @@ -753,10 +755,10 @@ impl Elaborator<'_> {
let func_id = path_resolution.item.function_id()?;
let meta = self.interner.try_function_meta(&func_id)?;
let the_trait = self.interner.get_trait(meta.trait_id?);
let method = the_trait.find_method(path.last_name())?;
let method = the_trait.find_method(path.last_name(), self.interner)?;
let constraint = the_trait.as_constraint(path.location);
let trait_method = TraitMethod { method_id: method, constraint, assumed: false };
let method = TraitPathResolutionMethod::TraitMethod(trait_method);
let trait_method = TraitItem { definition: method, constraint, assumed: false };
let method = TraitPathResolutionMethod::TraitItem(trait_method);
let item = Some(path_resolution.item);
Some(TraitPathResolution { method, item, errors: path_resolution.errors })
}
Expand All @@ -782,9 +784,11 @@ impl Elaborator<'_> {
}

let the_trait = self.interner.get_trait(constraint.trait_bound.trait_id);
if let Some(method) = the_trait.find_method(path.last_name()) {
let trait_method = TraitMethod { method_id: method, constraint, assumed: true };
let method = TraitPathResolutionMethod::TraitMethod(trait_method);
if let Some(definition) =
the_trait.find_method_or_constant(path.last_name(), self.interner)
{
let trait_item = TraitItem { definition, constraint, assumed: true };
let method = TraitPathResolutionMethod::TraitItem(trait_item);
return Some(TraitPathResolution { method, item: None, errors: Vec::new() });
}
}
Expand Down Expand Up @@ -863,22 +867,20 @@ impl Elaborator<'_> {
let method = TraitPathResolutionMethod::NotATraitMethod(func_id);
Some(TraitPathResolution { method, item: None, errors })
}
HirMethodReference::TraitMethodId(trait_method_id, _, _) => {
let trait_id = trait_method_id.trait_id;
HirMethodReference::TraitItemId(definition, trait_id, _, _) => {
let trait_ = self.interner.get_trait(trait_id);
let mut constraint = trait_.as_constraint(location);
constraint.typ = typ.clone();

let trait_method =
TraitMethod { method_id: trait_method_id, constraint, assumed: false };
let trait_method = TraitItem { definition, constraint, assumed: false };
let item = PathResolutionItem::TypeTraitFunction(typ, trait_id, func_id);

let mut errors = path_resolution.errors;
if let Some(error) = error {
errors.push(error);
}

let method = TraitPathResolutionMethod::TraitMethod(trait_method);
let method = TraitPathResolutionMethod::TraitItem(trait_method);
Some(TraitPathResolution { method, item: Some(item), errors })
}
}
Expand Down Expand Up @@ -1515,14 +1517,12 @@ impl Elaborator<'_> {
pub(super) fn type_check_operator_method(
&mut self,
expr_id: ExprId,
trait_method_id: TraitMethodId,
trait_method_id: TraitItemId,
object_type: &Type,
location: Location,
) {
let the_trait = self.interner.get_trait(trait_method_id.trait_id);

let method = &the_trait.methods[trait_method_id.method_index];
let (method_type, mut bindings) = method.typ.clone().instantiate(self.interner);
let method_type = self.interner.definition_type(trait_method_id.item_id);
let (method_type, mut bindings) = method_type.instantiate(self.interner);

match method_type {
Type::Function(args, _, _, _) => {
Expand Down Expand Up @@ -1829,8 +1829,8 @@ impl Elaborator<'_> {
// Return a TraitMethodId with unbound generics. These will later be bound by the type-checker.
let trait_ = self.interner.get_trait(trait_id);
let generics = trait_.get_trait_generics(location);
let trait_method_id = trait_.find_method(method_name).unwrap();
HirMethodReference::TraitMethodId(trait_method_id, generics, false)
let trait_method_id = trait_.find_method(method_name, self.interner).unwrap();
HirMethodReference::TraitItemId(trait_method_id, trait_id, generics, false)
}

fn lookup_method_in_trait_constraints(
Expand All @@ -1851,16 +1851,20 @@ impl Elaborator<'_> {
if Some(object_type) == self.self_type.as_ref() {
let the_trait = self.interner.get_trait(trait_id);
let constraint = the_trait.as_constraint(the_trait.name.location());
if let Some(HirMethodReference::TraitMethodId(method_id, generics, _)) = self
.lookup_method_in_trait(
if let Some(HirMethodReference::TraitItemId(method_id, trait_id, generics, _)) =
self.lookup_method_in_trait(
the_trait,
method_name,
&constraint.trait_bound,
the_trait.id,
)
{
// If it is, it's an assumed trait
return Some(HirMethodReference::TraitMethodId(method_id, generics, true));
// Note that here we use the `trait_id` from `TraitItemId` because looking a method on a trait
// might return a method on a parent trait.
return Some(HirMethodReference::TraitItemId(
method_id, trait_id, generics, true,
));
}
}
}
Expand Down Expand Up @@ -1904,12 +1908,11 @@ impl Elaborator<'_> {
trait_bound: &ResolvedTraitBound,
starting_trait_id: TraitId,
) -> Option<HirMethodReference> {
if let Some(trait_method) = the_trait.find_method(method_name) {
return Some(HirMethodReference::TraitMethodId(
trait_method,
trait_bound.trait_generics.clone(),
false,
));
if let Some(trait_method) = the_trait.find_method(method_name, self.interner) {
let trait_generics = trait_bound.trait_generics.clone();
let trait_item_id =
HirMethodReference::TraitItemId(trait_method, the_trait.id, trait_generics, false);
return Some(trait_item_id);
}

// Search in the parent traits, if any
Expand Down
Loading
Loading