Skip to content

Commit ac60ef5

Browse files
author
jfecher
authored
fix: Variables from trait constraints being permanently bound over when used within a trait impl (#4450)
# Description ## Problem\* Resolves #4436 ## Summary\* This issue stemmed from calling another trait method within an impl for the trait. The trait method required a trait constraint of the same trait to be valid and was using the trait with its original type variables. These would later be bound over when an impl was searched for for this trait. I've added a somewhat hacky solution of avoiding inserting `t = t` bindings from the trait constraint when checking identifiers. Avoiding inserting this binding means `t` in this case will later be instantiated to a fresh type variable later on in the `instantiate_with_bindings` call. ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
1 parent 21fc4b8 commit ac60ef5

4 files changed

Lines changed: 41 additions & 2 deletions

File tree

compiler/noirc_frontend/src/hir/type_check/expr.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,10 @@ impl<'interner> TypeChecker<'interner> {
326326
assert_eq!(the_trait.generics.len(), constraint.trait_generics.len());
327327

328328
for (param, arg) in the_trait.generics.iter().zip(&constraint.trait_generics) {
329-
bindings.insert(param.id(), (param.clone(), arg.clone()));
329+
// Avoid binding t = t
330+
if !arg.occurs(param.id()) {
331+
bindings.insert(param.id(), (param.clone(), arg.clone()));
332+
}
330333
}
331334
}
332335

compiler/noirc_frontend/src/hir_def/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ impl Type {
15581558
}
15591559

15601560
/// True if the given TypeVariableId is free anywhere within self
1561-
fn occurs(&self, target_id: TypeVariableId) -> bool {
1561+
pub fn occurs(&self, target_id: TypeVariableId) -> bool {
15621562
match self {
15631563
Type::Array(len, elem) => len.occurs(target_id) || elem.occurs(target_id),
15641564
Type::String(len) => len.occurs(target_id),
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[package]
2+
name = "regression_4436"
3+
type = "bin"
4+
authors = [""]
5+
compiler_version = ">=0.22.0"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
trait LibTrait<N> {
2+
fn broadcast();
3+
fn get_constant() -> Field;
4+
}
5+
6+
global STRUCT_A_LEN: Field = 3;
7+
global STRUCT_B_LEN: Field = 5;
8+
9+
struct StructA;
10+
struct StructB;
11+
12+
impl LibTrait<u32> for StructA {
13+
fn broadcast() {
14+
Self::get_constant();
15+
}
16+
17+
fn get_constant() -> Field {
18+
1
19+
}
20+
}
21+
impl LibTrait<u64> for StructB {
22+
fn broadcast() {
23+
Self::get_constant();
24+
}
25+
26+
fn get_constant() -> Field {
27+
1
28+
}
29+
}
30+
31+
fn main() {}

0 commit comments

Comments
 (0)