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

fix: Fix crash when using undeclared traits #3509

Merged
merged 3 commits into from
Nov 20, 2023
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
33 changes: 21 additions & 12 deletions compiler/noirc_frontend/src/hir/type_check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,12 +317,19 @@ impl<'interner> TypeChecker<'interner> {
match self.interner.lookup_trait_implementation(object_type, trait_id) {
Ok(impl_kind) => self.interner.select_impl_for_ident(function_ident_id, impl_kind),
Err(erroring_constraints) => {
let constraints = vecmap(erroring_constraints, |constraint| {
let r#trait = self.interner.get_trait(constraint.trait_id);
(constraint.typ, r#trait.name.to_string())
});
// Don't show any errors where try_get_trait returns None.
// This can happen if a trait is used that was never declared.
let constraints = erroring_constraints
.into_iter()
.map(|constraint| {
let r#trait = self.interner.try_get_trait(constraint.trait_id)?;
Some((constraint.typ, r#trait.name.to_string()))
})
.collect::<Option<Vec<_>>>();

self.errors.push(TypeCheckError::NoMatchingImplFound { constraints, span });
if let Some(constraints) = constraints {
self.errors.push(TypeCheckError::NoMatchingImplFound { constraints, span });
}
}
}
}
Expand Down Expand Up @@ -902,13 +909,15 @@ impl<'interner> TypeChecker<'interner> {

for constraint in func_meta.trait_constraints {
if *object_type == constraint.typ {
let the_trait = self.interner.get_trait(constraint.trait_id);

for (method_index, method) in the_trait.methods.iter().enumerate() {
if method.name.0.contents == method_name {
let trait_method =
TraitMethodId { trait_id: constraint.trait_id, method_index };
return Some(HirMethodReference::TraitMethodId(trait_method));
if let Some(the_trait) = self.interner.try_get_trait(constraint.trait_id) {
for (method_index, method) in the_trait.methods.iter().enumerate() {
if method.name.0.contents == method_name {
let trait_method = TraitMethodId {
trait_id: constraint.trait_id,
method_index,
};
return Some(HirMethodReference::TraitMethodId(trait_method));
}
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions compiler/noirc_frontend/src/hir/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ pub fn type_check_func(interner: &mut NodeInterner, func_id: FuncId) -> Vec<Type
let trait_id = constraint.trait_id;

if !type_checker.interner.add_assumed_trait_implementation(object, trait_id) {
let trait_name = type_checker.interner.get_trait(trait_id).name.to_string();
let typ = constraint.typ.clone();
let span = meta.name.location.span;
errors.push(TypeCheckError::UnneededTraitConstraint { trait_name, typ, span });
if let Some(the_trait) = type_checker.interner.try_get_trait(trait_id) {
let trait_name = the_trait.name.to_string();
let typ = constraint.typ.clone();
let span = meta.name.location.span;
errors.push(TypeCheckError::UnneededTraitConstraint { trait_name, typ, span });
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions compiler/noirc_frontend/src/node_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,10 @@ impl NodeInterner {
self.traits[&id].clone()
}

pub fn try_get_trait(&self, id: TraitId) -> Option<Trait> {
self.traits.get(&id).cloned()
}

pub fn get_type_alias(&self, id: TypeAliasId) -> &TypeAliasType {
&self.type_aliases[id.0]
}
Expand Down
Loading