Skip to content
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
5 changes: 3 additions & 2 deletions compiler/noirc_frontend/src/elaborator/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,8 +713,9 @@
| PathResolutionItem::PrimitiveType(_)
| PathResolutionItem::Trait(_)
| PathResolutionItem::ModuleFunction(_)
| PathResolutionItem::TypeAliasFunction(_, _, _)
| PathResolutionItem::TraitFunction(_, _, _)
| PathResolutionItem::TypeAliasFunction(..)
| PathResolutionItem::TraitFunction(..)
| PathResolutionItem::TypeTraitFunction(..)
| PathResolutionItem::PrimitiveFunction(..) => {
// This variable refers to an existing item
if let Some(name) = name {
Expand Down Expand Up @@ -1009,7 +1010,7 @@

/// Compiles the cases and fallback cases for integer and range patterns.
///
/// Integers have an infinite number of constructors, so we specialise the

Check warning on line 1013 in compiler/noirc_frontend/src/elaborator/enums.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (specialise)
/// compilation of integer and range patterns.
fn compile_int_cases(
&mut self,
Expand Down
13 changes: 13 additions & 0 deletions compiler/noirc_frontend/src/elaborator/path_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,22 @@
Trait(TraitId),

// These are values
/// A reference to a global value.
Global(GlobalId),
/// A function call on a module, for example `some::module::function()`.
ModuleFunction(FuncId),
Method(TypeId, Option<Turbofish>, FuncId),
/// A function call on `Self`, for example `Self::function()`. Turbofish is not allowed here.
SelfMethod(FuncId),
/// A function call on a type alias, for example `TypeAlias::function()`.
TypeAliasFunction(TypeAliasId, Option<Turbofish>, FuncId),
/// A function call on a trait, for example `Trait::function()` or `Trait::<A, B>::function()`.
TraitFunction(TraitId, Option<Turbofish>, FuncId),
/// A function call on a type that resolves to a trait method, for example `SomeType::from(...)`
/// or `SomeType::<A, B>::from(..).`. The main difference from `TraitFunction` is that this
/// holds the self type, in this case `SomeType`.
TypeTraitFunction(Type, TraitId, Option<Turbofish>, FuncId),
/// A function call on a primitive type, for example `u64::from(...)` or `u64::<A, B>::from(..)`.
PrimitiveFunction(PrimitiveType, Option<Turbofish>, FuncId),
}

Expand All @@ -52,6 +62,7 @@
| PathResolutionItem::SelfMethod(func_id)
| PathResolutionItem::TypeAliasFunction(_, _, func_id)
| PathResolutionItem::TraitFunction(_, _, func_id)
| PathResolutionItem::TypeTraitFunction(_, _, _, func_id)
| PathResolutionItem::PrimitiveFunction(_, _, func_id) => Some(*func_id),
PathResolutionItem::Module(..)
| PathResolutionItem::Type(..)
Expand All @@ -75,6 +86,7 @@
| PathResolutionItem::SelfMethod(..)
| PathResolutionItem::TypeAliasFunction(..)
| PathResolutionItem::TraitFunction(..)
| PathResolutionItem::TypeTraitFunction(..)
| PathResolutionItem::PrimitiveFunction(..) => "function",
}
}
Expand Down Expand Up @@ -113,7 +125,7 @@
FoundMultipleTraitMethods(Vec<(TraitId, Ident)>),
}

/// Determines whether datatypes found along a path are to be marked as referenced

Check warning on line 128 in compiler/noirc_frontend/src/elaborator/path_resolution.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (datatypes)
/// or used (see [`crate::usage_tracker::UsageTracker::mark_as_referenced`]
/// and [`crate::usage_tracker::UsageTracker::mark_as_used`])
///
Expand Down Expand Up @@ -145,7 +157,7 @@
MarkAsUsed,
}

/// Depenending on where a path appears in the source code it should either resolve to a type

Check warning on line 160 in compiler/noirc_frontend/src/elaborator/path_resolution.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Depenending)
/// or a value. For example, in `let x: Foo::Bar = Foo::Bar {}` both `Foo::Bar` should resolve to
/// types, never values. On the other hand, in `Foo::Bar()` `Foo::Bar` should resolve to a value,
/// typically a function.
Expand Down Expand Up @@ -388,6 +400,7 @@
| PathResolutionItem::SelfMethod(..)
| PathResolutionItem::TypeAliasFunction(..)
| PathResolutionItem::TraitFunction(..)
| PathResolutionItem::TypeTraitFunction(..)
| PathResolutionItem::PrimitiveFunction(..) => (),
}
resolution
Expand Down
75 changes: 60 additions & 15 deletions compiler/noirc_frontend/src/elaborator/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
ERROR_IDENT, Expression, ExpressionKind, GenericTypeArgs, Ident, ItemVisibility, Path,
PathSegment, Pattern, TypePath,
},
elaborator::types::SELF_TYPE_NAME,
hir::{
def_collector::dc_crate::CompilationError,
resolution::{errors::ResolverError, import::PathResolutionError},
Expand Down Expand Up @@ -579,7 +580,11 @@ impl Elaborator<'_> {
let (expr, item) = self.resolve_variable(variable);
let definition_id = expr.id;

let type_generics = item.map(|item| self.resolve_item_turbofish(item)).unwrap_or_default();
let (type_generics, self_generic) = if let Some(item) = item {
self.resolve_item_turbofish_and_self_type(item)
} else {
(Vec::new(), None)
};

let definition = self.interner.try_definition(definition_id);
let is_comptime_local = !self.in_comptime_context()
Expand All @@ -596,9 +601,21 @@ impl Elaborator<'_> {
None
};

// If this is a function call on a type that has generics, we need to bind those generic types.
if !type_generics.is_empty() {
if let Some(DefinitionKind::Function(func_id)) = &definition_kind {
if let Some(DefinitionKind::Function(func_id)) = &definition_kind {
// If there's a self type, bind it to the self type generic
if let Some(self_generic) = self_generic {
let func_generics = &self.interner.function_meta(func_id).all_generics;
let self_resolved_generic =
func_generics.iter().find(|generic| generic.name.as_str() == SELF_TYPE_NAME);
if let Some(self_resolved_generic) = self_resolved_generic {
let type_var = &self_resolved_generic.type_var;
bindings
.insert(type_var.id(), (type_var.clone(), type_var.kind(), self_generic));
}
}

// If this is a function call on a type that has generics, we need to bind those generic types.
if !type_generics.is_empty() {
// `all_generics` will always have the enclosing type generics first, so we need to bind those
let func_generics = &self.interner.function_meta(func_id).all_generics;
for (type_generic, func_generic) in type_generics.into_iter().zip(func_generics) {
Expand Down Expand Up @@ -745,25 +762,30 @@ impl Elaborator<'_> {
/// foo::Bar::<i32>::baz
/// ```
/// Solve `<i32>` above
fn resolve_item_turbofish(&mut self, item: PathResolutionItem) -> Vec<Type> {
fn resolve_item_turbofish_and_self_type(
&mut self,
item: PathResolutionItem,
) -> (Vec<Type>, Option<Type>) {
match item {
PathResolutionItem::Method(struct_id, Some(generics), _func_id) => {
let struct_type = self.interner.get_type(struct_id);
let struct_type = struct_type.borrow();
let struct_generics = struct_type.instantiate(self.interner);
self.resolve_struct_turbofish_generics(
let generics = self.resolve_struct_turbofish_generics(
&struct_type,
struct_generics,
Some(generics.generics),
generics.location,
)
);
(generics, None)
}
PathResolutionItem::SelfMethod(_) => {
if let Some(Type::DataType(_, generics)) = &self.self_type {
let generics = if let Some(Type::DataType(_, generics)) = &self.self_type {
generics.clone()
} else {
Vec::new()
}
};
(generics, None)
}
PathResolutionItem::TypeAliasFunction(type_alias_id, generics, _func_id) => {
let type_alias = self.interner.get_type_alias(type_alias_id);
Expand All @@ -788,24 +810,46 @@ impl Elaborator<'_> {
// have more generics than those in the alias, like in this example:
//
// type Alias<T> = Struct<T, i32>;
get_type_alias_generics(&type_alias, &generics)
let generics = get_type_alias_generics(&type_alias, &generics);
(generics, None)
}
PathResolutionItem::TraitFunction(trait_id, Some(generics), _func_id) => {
let trait_ = self.interner.get_trait(trait_id);
let kinds = vecmap(&trait_.generics, |generic| generic.kind());
let trait_generics =
vecmap(&kinds, |kind| self.interner.next_type_variable_with_kind(kind.clone()));

self.resolve_trait_turbofish_generics(
let generics = self.resolve_trait_turbofish_generics(
&trait_.name.to_string(),
kinds,
trait_generics,
Some(generics.generics),
generics.location,
)
);
(generics, None)
}
PathResolutionItem::TypeTraitFunction(self_type, trait_id, generics, _func_id) => {
let generics = if let Some(generics) = generics {
let trait_ = self.interner.get_trait(trait_id);
let kinds = vecmap(&trait_.generics, |generic| generic.kind());
let trait_generics = vecmap(&kinds, |kind| {
self.interner.next_type_variable_with_kind(kind.clone())
});

self.resolve_trait_turbofish_generics(
&trait_.name.to_string(),
kinds,
trait_generics,
Some(generics.generics),
generics.location,
)
} else {
Vec::new()
};
(generics, Some(self_type))
}
PathResolutionItem::PrimitiveFunction(primitive_type, turbofish, _func_id) => {
match primitive_type {
let generics = match primitive_type {
PrimitiveType::Bool
| PrimitiveType::CtString
| PrimitiveType::Expr
Expand Down Expand Up @@ -879,7 +923,8 @@ impl Elaborator<'_> {
Vec::new()
}
}
}
};
(generics, None)
}
PathResolutionItem::Method(_, None, _)
| PathResolutionItem::TraitFunction(_, None, _)
Expand All @@ -889,7 +934,7 @@ impl Elaborator<'_> {
| PathResolutionItem::PrimitiveType(..)
| PathResolutionItem::Trait(..)
| PathResolutionItem::Global(..)
| PathResolutionItem::ModuleFunction(..) => Vec::new(),
| PathResolutionItem::ModuleFunction(..) => (Vec::new(), None),
}
}

Expand Down
5 changes: 3 additions & 2 deletions compiler/noirc_frontend/src/elaborator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -906,15 +906,16 @@
let trait_id = trait_method_id.trait_id;
let trait_ = self.interner.get_trait(trait_id);
let mut constraint = trait_.as_constraint(location);
constraint.typ = typ;
constraint.typ = typ.clone();

let method = TraitMethod { method_id: trait_method_id, constraint, assumed: false };
let turbofish = before_last_segment.turbofish();
let item = PathResolutionItem::TraitFunction(trait_id, turbofish, func_id);
let item = PathResolutionItem::TypeTraitFunction(typ, trait_id, turbofish, func_id);
let mut errors = path_resolution.errors;
if let Some(error) = error {
errors.push(error);
}

Some(TraitPathResolution { method, item: Some(item), errors })
}

Expand Down Expand Up @@ -2207,7 +2208,7 @@
let existing = existing.follow_bindings();
let new = binding.2.follow_bindings();

// Exact equality on types is intential here, we never want to

Check warning on line 2211 in compiler/noirc_frontend/src/elaborator/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (intential)
// overwrite even type variables but should probably avoid a panic if
// the types are exactly the same.
if existing != new {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "type_trait_method_call_multiple_candidates"
type = "bin"
authors = [""]

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use dep::std::convert::From;

struct MyU128 {
lo: Field,
hi: Field,
}

impl MyU128 {
pub fn from_u64s_le(lo: u64, hi: u64) -> MyU128 {
MyU128 { lo: lo as Field, hi: hi as Field }
}
}

impl From<u64> for MyU128 {
fn from(value: u64) -> MyU128 {
MyU128::from_u64s_le(value, 0)
}
}

impl From<u32> for MyU128 {
fn from(value: u32) -> MyU128 {
MyU128::from(value as u64)
}
}

fn main() {
let x: u64 = 0;
let mut small_int = MyU128::from(x);
assert(small_int.lo == x as Field);
let u32_3: u32 = 3;
assert(MyU128::from(u32_3).lo == 3);
}
4 changes: 3 additions & 1 deletion tooling/nargo_cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
// There's no "src/main.nr" here so it's trickier to make this work
"overlapping_dep_and_mod",
// bug
"poseidonsponge_x5_254",

Check warning on line 131 in tooling/nargo_cli/build.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (poseidonsponge)
// bug
"regression_5045",
// bug
Expand All @@ -147,7 +147,7 @@
/// These tests are ignored because of existing bugs in `nargo expand`.
/// As the bugs are fixed these tests should be removed from this list.
/// (some are ignored on purpose for the same reason as `IGNORED_NARGO_EXPAND_EXECUTION_TESTS`)
const IGNORED_NARGO_EXPAND_COMPILE_SUCCESS_EMPTY_TESTS: [&str; 20] = [
const IGNORED_NARGO_EXPAND_COMPILE_SUCCESS_EMPTY_TESTS: [&str; 21] = [
// bug
"associated_type_bounds",
// bug
Expand Down Expand Up @@ -184,6 +184,8 @@
"trait_override_implementation",
// bug
"trait_static_methods",
// bug
"type_trait_method_call_multiple_candidates",
// There's no "src/main.nr" here so it's trickier to make this work
"workspace_reexport_bug",
// bug
Expand Down Expand Up @@ -691,7 +693,7 @@
writeln!(test_file, "}}").unwrap();
}

/// Here we check, for every program in `test_programs/exeuction_success`, that:

Check warning on line 696 in tooling/nargo_cli/build.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (exeuction)
/// 1. `nargo expand` works on it
/// 2. That the output of the original program is the same as the output of the expanded program
/// (that is, we run `nargo execute` on the original program and the expanded program and compare the output)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading