From 52c133233707a47745612c820ddd6f9e5ff3fb49 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 23 Dec 2024 16:13:46 -0300 Subject: [PATCH] feat!: type-check trait default methods --- compiler/noirc_frontend/src/ast/expression.rs | 8 +- compiler/noirc_frontend/src/elaborator/mod.rs | 6 + .../noirc_frontend/src/elaborator/patterns.rs | 2 +- .../noirc_frontend/src/elaborator/traits.rs | 39 +++--- .../noirc_frontend/src/elaborator/types.rs | 29 ++++- .../src/hir/def_collector/dc_mod.rs | 4 +- compiler/noirc_frontend/src/hir_def/expr.rs | 9 +- .../noirc_frontend/src/hir_def/function.rs | 4 +- compiler/noirc_frontend/src/node_interner.rs | 20 --- compiler/noirc_frontend/src/tests.rs | 3 +- compiler/noirc_frontend/src/tests/traits.rs | 67 +++++++++- .../trait_function_calls/src/main.nr | 117 ++++++++++++++---- 12 files changed, 235 insertions(+), 73 deletions(-) diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index ae622f46686..9d521545e7a 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -821,8 +821,8 @@ impl FunctionDefinition { is_unconstrained: bool, generics: &UnresolvedGenerics, parameters: &[(Ident, UnresolvedType)], - body: &BlockExpression, - where_clause: &[UnresolvedTraitConstraint], + body: BlockExpression, + where_clause: Vec, return_type: &FunctionReturnType, ) -> FunctionDefinition { let p = parameters @@ -843,9 +843,9 @@ impl FunctionDefinition { visibility: ItemVisibility::Private, generics: generics.clone(), parameters: p, - body: body.clone(), + body, span: name.span(), - where_clause: where_clause.to_vec(), + where_clause, return_type: return_type.clone(), return_visibility: Visibility::Private, } diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 593ea6b20e8..182db0c1164 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -328,6 +328,12 @@ impl<'context> Elaborator<'context> { self.elaborate_functions(functions); } + for (trait_id, unresolved_trait) in items.traits { + self.current_trait = Some(trait_id); + self.elaborate_functions(unresolved_trait.fns_with_default_impl); + } + self.current_trait = None; + for impls in items.impls.into_values() { self.elaborate_impls(impls); } diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 133473219f6..242f5f0b496 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -856,7 +856,7 @@ impl<'context> Elaborator<'context> { let impl_kind = match method { HirMethodReference::FuncId(_) => ImplKind::NotATraitMethod, - HirMethodReference::TraitMethodId(method_id, generics) => { + HirMethodReference::TraitMethodId(method_id, generics, _) => { let mut constraint = self.interner.get_trait(method_id.trait_id).as_constraint(span); constraint.trait_bound.trait_generics = generics; diff --git a/compiler/noirc_frontend/src/elaborator/traits.rs b/compiler/noirc_frontend/src/elaborator/traits.rs index e1be45927ca..8cbe960ea6c 100644 --- a/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/compiler/noirc_frontend/src/elaborator/traits.rs @@ -28,6 +28,11 @@ impl<'context> Elaborator<'context> { self.recover_generics(|this| { this.current_trait = Some(*trait_id); + let the_trait = this.interner.get_trait(*trait_id); + let self_typevar = the_trait.self_type_typevar.clone(); + let self_type = Type::TypeVariable(self_typevar.clone()); + this.self_type = Some(self_type.clone()); + let resolved_generics = this.interner.get_trait(*trait_id).generics.clone(); this.add_existing_generics( &unresolved_trait.trait_def.generics, @@ -48,12 +53,15 @@ impl<'context> Elaborator<'context> { .add_trait_dependency(DependencyId::Trait(bound.trait_id), *trait_id); } + this.interner.update_trait(*trait_id, |trait_def| { + trait_def.set_trait_bounds(resolved_trait_bounds); + trait_def.set_where_clause(where_clause); + }); + let methods = this.resolve_trait_methods(*trait_id, unresolved_trait); this.interner.update_trait(*trait_id, |trait_def| { trait_def.set_methods(methods); - trait_def.set_trait_bounds(resolved_trait_bounds); - trait_def.set_where_clause(where_clause); }); }); @@ -94,7 +102,7 @@ impl<'context> Elaborator<'context> { parameters, return_type, where_clause, - body: _, + body, is_unconstrained, visibility: _, is_comptime: _, @@ -102,8 +110,9 @@ impl<'context> Elaborator<'context> { { self.recover_generics(|this| { let the_trait = this.interner.get_trait(trait_id); + let the_trait_where_clause = the_trait.where_clause.clone(); + let the_trait_constraint = the_trait.as_constraint(the_trait.name.span()); let self_typevar = the_trait.self_type_typevar.clone(); - let self_type = Type::TypeVariable(self_typevar.clone()); let name_span = the_trait.name.span(); this.add_existing_generic( @@ -115,9 +124,12 @@ impl<'context> Elaborator<'context> { span: name_span, }, ); - this.self_type = Some(self_type.clone()); let func_id = unresolved_trait.method_ids[&name.0.contents]; + let mut where_clause = where_clause.to_vec(); + + // Attach any trait constraints on the trait to the function + where_clause.extend(unresolved_trait.trait_def.where_clause.clone()); this.resolve_trait_function( trait_id, @@ -127,6 +139,7 @@ impl<'context> Elaborator<'context> { parameters, return_type, where_clause, + body, func_id, ); @@ -188,12 +201,14 @@ impl<'context> Elaborator<'context> { generics: &UnresolvedGenerics, parameters: &[(Ident, UnresolvedType)], return_type: &FunctionReturnType, - where_clause: &[UnresolvedTraitConstraint], + where_clause: Vec, + body: &Option, func_id: FuncId, ) { - let old_generic_count = self.generics.len(); - - self.scopes.start_function(); + let body = match body { + Some(body) => body.clone(), + None => BlockExpression { statements: Vec::new() }, + }; let kind = FunctionKind::Normal; let mut def = FunctionDefinition::normal( @@ -201,7 +216,7 @@ impl<'context> Elaborator<'context> { is_unconstrained, generics, parameters, - &BlockExpression { statements: Vec::new() }, + body, where_clause, return_type, ); @@ -210,10 +225,6 @@ impl<'context> Elaborator<'context> { let mut function = NoirFunction { kind, def }; self.define_function_meta(&mut function, func_id, Some(trait_id)); - self.elaborate_function(func_id); - let _ = self.scopes.end_function(); - // Don't check the scope tree for unused variables, they can't be used in a declaration anyway. - self.generics.truncate(old_generic_count); } } diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 550ee41fbd4..c3375fc35ad 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -566,12 +566,17 @@ impl<'context> Elaborator<'context> { } // this resolves Self::some_static_method, inside an impl block (where we don't have a concrete self_type) + // or inside a trait default method. // // Returns the trait method, trait constraint, and whether the impl is assumed to exist by a where clause or not // E.g. `t.method()` with `where T: Foo` in scope will return `(Foo::method, T, vec![Bar])` fn resolve_trait_static_method_by_self(&mut self, path: &Path) -> Option { - let trait_impl = self.current_trait_impl?; - let trait_id = self.interner.try_get_trait_implementation(trait_impl)?.borrow().trait_id; + let trait_id = if let Some(current_trait) = self.current_trait { + current_trait + } else { + let trait_impl = self.current_trait_impl?; + self.interner.try_get_trait_implementation(trait_impl)?.borrow().trait_id + }; if path.kind == PathKind::Plain && path.segments.len() == 2 { let name = &path.segments[0].ident.0.contents; @@ -1395,6 +1400,25 @@ impl<'context> Elaborator<'context> { }; let func_meta = self.interner.function_meta(&func_id); + // If inside a trait method, check if it's a method on `self` + if let Some(trait_id) = func_meta.trait_id { + 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.span()); + if let Some(HirMethodReference::TraitMethodId(method_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)); + } + } + } + for constraint in &func_meta.trait_constraints { if *object_type == constraint.typ { if let Some(the_trait) = @@ -1432,6 +1456,7 @@ impl<'context> Elaborator<'context> { return Some(HirMethodReference::TraitMethodId( trait_method, trait_bound.trait_generics.clone(), + false, )); } diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index e7953aab5a4..df1200d6255 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -518,8 +518,8 @@ impl<'a> ModCollector<'a> { *is_unconstrained, generics, parameters, - body, - where_clause, + body.clone(), + where_clause.clone(), return_type, )); unresolved_functions.push_fn( diff --git a/compiler/noirc_frontend/src/hir_def/expr.rs b/compiler/noirc_frontend/src/hir_def/expr.rs index e243fc88cff..9b3bf4962bb 100644 --- a/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/compiler/noirc_frontend/src/hir_def/expr.rs @@ -209,14 +209,14 @@ pub enum HirMethodReference { /// Or a method can come from a Trait impl block, in which case /// the actual function called will depend on the instantiated type, /// which can be only known during monomorphization. - TraitMethodId(TraitMethodId, TraitGenerics), + TraitMethodId(TraitMethodId, TraitGenerics, bool /* assumed */), } impl HirMethodReference { pub fn func_id(&self, interner: &NodeInterner) -> Option { match self { HirMethodReference::FuncId(func_id) => Some(*func_id), - HirMethodReference::TraitMethodId(method_id, _) => { + HirMethodReference::TraitMethodId(method_id, _, _) => { let id = interner.trait_method_id(*method_id); match &interner.try_definition(id)?.kind { DefinitionKind::Function(func_id) => Some(*func_id), @@ -246,7 +246,7 @@ impl HirMethodCallExpression { HirMethodReference::FuncId(func_id) => { (interner.function_definition_id(func_id), ImplKind::NotATraitMethod) } - HirMethodReference::TraitMethodId(method_id, trait_generics) => { + HirMethodReference::TraitMethodId(method_id, trait_generics, assumed) => { let id = interner.trait_method_id(method_id); let constraint = TraitConstraint { typ: object_type, @@ -256,7 +256,8 @@ impl HirMethodCallExpression { span: location.span, }, }; - (id, ImplKind::TraitMethod(TraitMethod { method_id, constraint, assumed: false })) + + (id, ImplKind::TraitMethod(TraitMethod { method_id, constraint, assumed })) } }; let func_var = HirIdent { location, id, impl_kind }; diff --git a/compiler/noirc_frontend/src/hir_def/function.rs b/compiler/noirc_frontend/src/hir_def/function.rs index db6c3507b15..f6ee003b179 100644 --- a/compiler/noirc_frontend/src/hir_def/function.rs +++ b/compiler/noirc_frontend/src/hir_def/function.rs @@ -175,12 +175,12 @@ pub enum FunctionBody { impl FuncMeta { /// A stub function does not have a body. This includes Builtin, LowLevel, - /// and Oracle functions in addition to method declarations within a trait. + /// and Oracle functions. /// /// We don't check the return type of these functions since it will always have /// an empty body, and we don't check for unused parameters. pub fn is_stub(&self) -> bool { - self.kind.can_ignore_return_type() || self.trait_id.is_some() + self.kind.can_ignore_return_type() } pub fn function_signature(&self) -> FunctionSignature { diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 1df2cd76721..3ed183df49c 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use std::fmt; use std::hash::Hash; use std::marker::Copy; -use std::ops::Deref; use fm::FileId; use iter_extended::vecmap; @@ -1478,25 +1477,6 @@ impl NodeInterner { Ok(impl_kind) } - /// Given a `ObjectType: TraitId` pair, find all implementations without taking constraints into account or - /// applying any type bindings. Useful to look for a specific trait in a type that is used in a macro. - pub fn lookup_all_trait_implementations( - &self, - object_type: &Type, - trait_id: TraitId, - ) -> Vec<&TraitImplKind> { - let trait_impl = self.trait_implementation_map.get(&trait_id); - - let trait_impl = trait_impl.map(|trait_impl| { - let impls = trait_impl.iter().filter_map(|(typ, impl_kind)| match &typ { - Type::Forall(_, typ) => (typ.deref() == object_type).then_some(impl_kind), - _ => None, - }); - impls.collect() - }); - trait_impl.unwrap_or_default() - } - /// Similar to `lookup_trait_implementation` but does not apply any type bindings on success. /// On error returns either: /// - 1+ failing trait constraints, including the original. diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 3d908d1aa0c..589b3128eb0 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -2942,7 +2942,7 @@ fn uses_self_type_inside_trait() { fn uses_self_type_in_trait_where_clause() { let src = r#" pub trait Trait { - fn trait_func() -> bool; + fn trait_func(self) -> bool; } pub trait Foo where Self: Trait { @@ -2963,6 +2963,7 @@ fn uses_self_type_in_trait_where_clause() { "#; let errors = get_program_errors(src); + dbg!(&errors); assert_eq!(errors.len(), 2); let CompilationError::ResolverError(ResolverError::TraitNotImplemented { .. }) = &errors[0].0 diff --git a/compiler/noirc_frontend/src/tests/traits.rs b/compiler/noirc_frontend/src/tests/traits.rs index 811a32bab86..b641f726e47 100644 --- a/compiler/noirc_frontend/src/tests/traits.rs +++ b/compiler/noirc_frontend/src/tests/traits.rs @@ -592,7 +592,7 @@ fn trait_bounds_which_are_dependent_on_generic_types_are_resolved_correctly() { // Regression test for https://github.com/noir-lang/noir/issues/6420 let src = r#" trait Foo { - fn foo() -> Field; + fn foo(self) -> Field; } trait Bar: Foo { @@ -613,7 +613,8 @@ fn trait_bounds_which_are_dependent_on_generic_types_are_resolved_correctly() { where T: MarkerTrait, { - fn foo() -> Field { + fn foo(self) -> Field { + let _ = self; 42 } } @@ -652,3 +653,65 @@ fn does_not_crash_on_as_trait_path_with_empty_path() { ); assert!(!errors.is_empty()); } + +#[test] +fn type_checks_trait_default_method_and_errors() { + let src = r#" + pub trait Foo { + fn foo(self) -> i32 { + let _ = self; + true + } + } + + fn main() {} + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + + let CompilationError::TypeError(TypeCheckError::TypeMismatchWithSource { + expected, + actual, + .. + }) = &errors[0].0 + else { + panic!("Expected a type mismatch error, got {:?}", errors[0].0); + }; + + assert_eq!(expected.to_string(), "i32"); + assert_eq!(actual.to_string(), "bool"); +} + +#[test] +fn type_checks_trait_default_method_and_does_not_error() { + let src = r#" + pub trait Foo { + fn foo(self) -> i32 { + let _ = self; + 1 + } + } + + fn main() {} + "#; + assert_no_errors(src); +} + +#[test] +fn type_checks_trait_default_method_and_does_not_error_using_self() { + let src = r#" + pub trait Foo { + fn foo(self) -> i32 { + self.bar() + } + + fn bar(self) -> i32 { + let _ = self; + 1 + } + } + + fn main() {} + "#; + assert_no_errors(src); +} diff --git a/test_programs/compile_success_empty/trait_function_calls/src/main.nr b/test_programs/compile_success_empty/trait_function_calls/src/main.nr index f9a338bfa47..6c35ee97222 100644 --- a/test_programs/compile_success_empty/trait_function_calls/src/main.nr +++ b/test_programs/compile_success_empty/trait_function_calls/src/main.nr @@ -23,25 +23,31 @@ // 1a) trait default method -> trait default method trait Trait1a { fn trait_method1(self) -> Field { - self.trait_method2() * 7892 - self.vl + self.trait_method2() * 7892 - self.vl() } fn trait_method2(self) -> Field { let _ = self; 43278 } + fn vl(self) -> Field; } struct Struct1a { vl: Field, } -impl Trait1a for Struct1a {} +impl Trait1a for Struct1a { + fn vl(self) -> Field { + self.vl + } +} // 1b) trait default method -> trait overriden method trait Trait1b { fn trait_method1(self) -> Field { - self.trait_method2() * 2832 - self.vl + self.trait_method2() * 2832 - self.vl() } fn trait_method2(self) -> Field { 9323 } + fn vl(self) -> Field; } struct Struct1b { vl: Field, @@ -51,13 +57,17 @@ impl Trait1b for Struct1b { let _ = self; 2394 } + fn vl(self) -> Field { + self.vl + } } // 1c) trait default method -> trait overriden (no default) method trait Trait1c { fn trait_method1(self) -> Field { - self.trait_method2() * 7635 - self.vl + self.trait_method2() * 7635 - self.vl() } fn trait_method2(self) -> Field; + fn vl(self) -> Field; } struct Struct1c { vl: Field, @@ -67,16 +77,20 @@ impl Trait1c for Struct1c { let _ = self; 5485 } + fn vl(self) -> Field { + self.vl + } } // 1d) trait overriden method -> trait default method trait Trait1d { fn trait_method1(self) -> Field { - self.trait_method2() * 2825 - self.vl + self.trait_method2() * 2825 - self.vl() } fn trait_method2(self) -> Field { let _ = self; 29341 } + fn vl(self) -> Field; } struct Struct1d { vl: Field, @@ -85,15 +99,19 @@ impl Trait1d for Struct1d { fn trait_method1(self) -> Field { self.trait_method2() * 9342 - self.vl } + fn vl(self) -> Field { + self.vl + } } // 1e) trait overriden method -> trait overriden method trait Trait1e { fn trait_method1(self) -> Field { - self.trait_method2() * 85465 - self.vl + self.trait_method2() * 85465 - self.vl() } fn trait_method2(self) -> Field { 2381 } + fn vl(self) -> Field; } struct Struct1e { vl: Field, @@ -106,13 +124,17 @@ impl Trait1e for Struct1e { let _ = self; 58945 } + fn vl(self) -> Field { + self.vl + } } // 1f) trait overriden method -> trait overriden (no default) method trait Trait1f { fn trait_method1(self) -> Field { - self.trait_method2() * 43257 - self.vl + self.trait_method2() * 43257 - self.vl() } fn trait_method2(self) -> Field; + fn vl(self) -> Field; } struct Struct1f { vl: Field, @@ -125,6 +147,9 @@ impl Trait1f for Struct1f { let _ = self; 5748 } + fn vl(self) -> Field { + self.vl + } } // 1g) trait overriden (no default) method -> trait default method trait Trait1g { @@ -182,24 +207,30 @@ impl Trait1i for Struct1i { // 2a) trait default method -> trait default function trait Trait2a { fn trait_method1(self) -> Field { - Self::trait_function2() * 2385 - self.vl + Self::trait_function2() * 2385 - self.vl() } fn trait_function2() -> Field { 7843 } + fn vl(self) -> Field; } struct Struct2a { vl: Field, } -impl Trait2a for Struct2a {} +impl Trait2a for Struct2a { + fn vl(self) -> Field { + self.vl + } +} // 2b) trait default method -> trait overriden function trait Trait2b { fn trait_method1(self) -> Field { - Self::trait_function2() * 6583 - self.vl + Self::trait_function2() * 6583 - self.vl() } fn trait_function2() -> Field { 3752 } + fn vl(self) -> Field; } struct Struct2b { vl: Field, @@ -208,13 +239,17 @@ impl Trait2b for Struct2b { fn trait_function2() -> Field { 8477 } + fn vl(self) -> Field { + self.vl + } } // 2c) trait default method -> trait overriden (no default) function trait Trait2c { fn trait_method1(self) -> Field { - Self::trait_function2() * 2831 - self.vl + Self::trait_function2() * 2831 - self.vl() } fn trait_function2() -> Field; + fn vl(self) -> Field; } struct Struct2c { vl: Field, @@ -223,15 +258,19 @@ impl Trait2c for Struct2c { fn trait_function2() -> Field { 8342 } + fn vl(self) -> Field { + self.vl + } } // 2d) trait overriden method -> trait default function trait Trait2d { fn trait_method1(self) -> Field { - Self::trait_function2() * 924 - self.vl + Self::trait_function2() * 924 - self.vl() } fn trait_function2() -> Field { 384 } + fn vl(self) -> Field; } struct Struct2d { vl: Field, @@ -240,15 +279,19 @@ impl Trait2d for Struct2d { fn trait_method1(self) -> Field { Self::trait_function2() * 3984 - self.vl } + fn vl(self) -> Field { + self.vl + } } // 2e) trait overriden method -> trait overriden function trait Trait2e { fn trait_method1(self) -> Field { - Self::trait_function2() * 3642 - self.vl + Self::trait_function2() * 3642 - self.vl() } fn trait_function2() -> Field { 97342 } + fn vl(self) -> Field; } struct Struct2e { vl: Field, @@ -260,13 +303,17 @@ impl Trait2e for Struct2e { fn trait_function2() -> Field { 39400 } + fn vl(self) -> Field { + self.vl + } } // 2f) trait overriden method -> trait overriden (no default) function trait Trait2f { fn trait_method1(self) -> Field { - Self::trait_function2() * 2783 - self.vl + Self::trait_function2() * 2783 - self.vl() } fn trait_function2() -> Field; + fn vl(self) -> Field; } struct Struct2f { vl: Field, @@ -278,6 +325,9 @@ impl Trait2f for Struct2f { fn trait_function2() -> Field { 72311 } + fn vl(self) -> Field { + self.vl + } } // 2g) trait overriden (no default) method -> trait default function trait Trait2g { @@ -332,25 +382,31 @@ impl Trait2i for Struct2i { // 3a) trait default function -> trait default method trait Trait3a { fn trait_function1(a: Field, b: Self) -> Field { - b.trait_method2() * 8344 - b.vl + a + b.trait_method2() * 8344 - b.vl() + a } fn trait_method2(self) -> Field { let _ = self; 19212 } + fn vl(self) -> Field; } struct Struct3a { vl: Field, } -impl Trait3a for Struct3a {} +impl Trait3a for Struct3a { + fn vl(self) -> Field { + self.vl + } +} // 3b) trait default function -> trait overriden method trait Trait3b { fn trait_function1(a: Field, b: Self) -> Field { - b.trait_method2() * 9233 - b.vl + a + b.trait_method2() * 9233 - b.vl() + a } fn trait_method2(self) -> Field { 9111 } + fn vl(self) -> Field; } struct Struct3b { vl: Field, @@ -360,13 +416,17 @@ impl Trait3b for Struct3b { let _ = self; 2392 } + fn vl(self) -> Field { + self.vl + } } // 3c) trait default function -> trait overriden (no default) method trait Trait3c { fn trait_function1(a: Field, b: Self) -> Field { - b.trait_method2() * 2822 - b.vl + a + b.trait_method2() * 2822 - b.vl() + a } fn trait_method2(self) -> Field; + fn vl(self) -> Field; } struct Struct3c { vl: Field, @@ -376,16 +436,20 @@ impl Trait3c for Struct3c { let _ = self; 7743 } + fn vl(self) -> Field { + self.vl + } } // 3d) trait overriden function -> trait default method trait Trait3d { fn trait_function1(a: Field, b: Self) -> Field { - b.trait_method2() * 291 - b.vl + a + b.trait_method2() * 291 - b.vl() + a } fn trait_method2(self) -> Field { let _ = self; 3328 } + fn vl(self) -> Field; } struct Struct3d { vl: Field, @@ -394,15 +458,19 @@ impl Trait3d for Struct3d { fn trait_function1(a: Field, b: Self) -> Field { b.trait_method2() * 4933 - b.vl + a } + fn vl(self) -> Field { + self.vl + } } // 3e) trait overriden function -> trait overriden method trait Trait3e { fn trait_function1(a: Field, b: Self) -> Field { - b.trait_method2() * 71231 - b.vl + a + b.trait_method2() * 71231 - b.vl() + a } fn trait_method2(self) -> Field { 373 } + fn vl(self) -> Field; } struct Struct3e { vl: Field, @@ -415,13 +483,17 @@ impl Trait3e for Struct3e { let _ = self; 80002 } + fn vl(self) -> Field { + self.vl + } } // 3f) trait overriden function -> trait overriden (no default) method trait Trait3f { fn trait_function1(a: Field, b: Self) -> Field { - b.trait_method2() * 28223 - b.vl + a + b.trait_method2() * 28223 - b.vl() + a } fn trait_method2(self) -> Field; + fn vl(self) -> Field; } struct Struct3f { vl: Field, @@ -434,6 +506,9 @@ impl Trait3f for Struct3f { let _ = self; 63532 } + fn vl(self) -> Field { + self.vl + } } // 3g) trait overriden (no default) function -> trait default method trait Trait3g {